- 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.
# To do: Consider expanding matrix here to improve transparency and reduce file sizes.
# E.g. '/admin/gitlab-ci/matrix/clang-8.gitlab-ci.yml
- local: '/admin/gitlab-ci/gromacs.gitlab-ci.yml'
+ - local: '/admin/gitlab-ci/gromacs.matrix.gitlab-ci.yml'
# Repository cleanliness. Source tidiness, linting, and policy compliance.
- local: '/admin/gitlab-ci/lint.gitlab-ci.yml'
# Web page and manual.
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)
message(FATAL_ERROR "HWLOC package support required, but not found.")
endif()
- if (HWLOC_VERSION VERSION_LESS "2")
+ if (HWLOC_FOUND AND HWLOC_VERSION VERSION_LESS "2")
message(STATUS "Support for hwloc versions 1.x is deprecated")
endif()
# 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)
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)
add_subdirectory(tests)
endif()
-if(GMX_PYTHON_PACKAGE AND NOT GMX_BUILD_MDRUN_ONLY)
+if(GMX_PYTHON_PACKAGE)
add_subdirectory(python_packaging)
endif()
--- /dev/null
-# 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
+ # Scope: configure, build, unit tests
+ # Test implementation choices (free to change as needed):
+ # OS: Ubuntu 18.04
+ # Build type: RelWithAssert
+ # Compiler: GCC 8
+ # MPI: thread_MPI
+ # GPU: CUDA 11.0
+ # SIMD: AVX2_256
+ # FFT: FFTW3
+ # Parallelism nt/ntomp: 4/2 (unit tests)
+
+ gromacs:gcc-8-cuda-11.0:release:configure:
+ extends:
+ - .gromacs:base:release:configure
+ - .use-gcc:base
+ - .use-mpi
+ - .use-cuda
+ - .rules:nightly-only-for-release
+ image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0
+ variables:
+ CMAKE: /usr/local/cmake-3.15.7/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:
+ - archive:package
+ - regressiontests:package
+ - prepare-release-version
+
+ gromacs:gcc-8-cuda-11.0:release:build:
+ extends:
+ - .variables:default
+ - .gromacs:base:build
+ - .before_script:default
+ - .use-ccache
+ - .rules:nightly-only-for-release
+ stage: release-build
+ variables:
+ CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+ BUILD_DIR: release-builds-gcc
+ image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0
+ needs:
+ - job: gromacs:gcc-8-cuda-11.0:release:configure
+
+ gromacs:gcc-8-cuda-11.0:release:test:
+ extends:
+ - .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
+ variables:
+ CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+ KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
+ KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
+ BUILD_DIR: release-builds-gcc
+ tags:
+ - k8s-scilifelab
+ needs:
+ - job: gromacs:gcc-8-cuda-11.0:release:configure
+ - job: gromacs:gcc-8-cuda-11.0:release:build
+
variables:
VENVPATH: "/root/venv/py3.8"
PY_VER: "3.8.2"
+
+ .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"
+
+ gmxapi-0.2:gcc-10:gmx2021:py-3.9.1:
+ extends:
+ - .gmxapi-0.2:gcc-10:gmx2021
+ - .rules:merge-requests:release-2021
+ variables:
+ VENVPATH: "/root/venv/py3.9"
+ PY_VER: "3.9.1"
* 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.
* \brief
* First part of the TPR file structure containing information about
* the general aspect of the system.
+ *
+ * When adding to or making breaking changes to reading this struct,
+ * update TpxGeneration.
*/
struct TpxFileHeader
{
#
# 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.
#
# To help us fund GROMACS development, we humbly ask that you cite
# the research papers on the package. Check out http://www.gromacs.org.
- #
+
# \author Victor Holanda <victor.holanda@cscs.ch>
# \author Joe Jordan <ejjordan@kth.se>
# \author Prashanth Kanduri <kanduri@cscs.ch>
integrator.cpp
interactions.cpp
molecules.cpp
+ particlesequencer.cpp
particletype.cpp
simulationstate.cpp
topologyhelpers.cpp
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
molecules.h
kerneloptions.h
nblib.h
+ particlesequencer.h
particletype.h
- ppmap.h
simulationstate.h
topology.h
- topologyhelpers.h
DESTINATION include/nblib)
endif()
/*
* 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 "gromacs/nbnxm/pairsearch.h"
#include "gromacs/pbcutil/pbc.h"
#include "gromacs/utility/logger.h"
+ #include "gromacs/utility/listoflists.h"
#include "gromacs/utility/smalloc.h"
#include "nblib/exception.h"
#include "nblib/kerneloptions.h"
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);
+ 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);
- // Put everything together
- auto nbv = std::make_unique<nonbonded_verlet_t>(
- std::move(pairlistSets), std::move(pairSearch), std::move(atomData), kernelSetup, nullptr, nullWallcycle);
-
// Needs to be called with the number of unique ParticleTypes
- nbnxn_atomdata_init(gmx::MDLogger(), atomData.get(), kernelSetup.kernelType, combinationRule,
- numParticleTypes, nonbondedParameters_, 1, numThreads);
+ nbnxn_atomdata_init(gmx::MDLogger(),
- nbv->nbat.get(),
++ atomData.get(),
+ kernelSetup.kernelType,
+ combinationRule,
+ numParticleTypes,
+ nonbondedParameters_,
+ 1,
+ numThreads);
- auto nbv = std::make_unique<nonbonded_verlet_t>(std::move(pairlistSets), std::move(pairSearch),
- std::move(atomData), kernelSetup, nullptr,
- nullWallcycle);
+ // Put everything together
++ auto nbv = std::make_unique<nonbonded_verlet_t>(
++ std::move(pairlistSets), std::move(pairSearch), std::move(atomData), kernelSetup, nullptr, nullWallcycle);
+
gmxForceCalculator_->nbv_ = std::move(nbv);
}
gmxForceCalculator_->interactionConst_->epsfac = 0;
}
- calc_rffac(nullptr, gmxForceCalculator_->interactionConst_->epsilon_r,
+ calc_rffac(nullptr,
+ gmxForceCalculator_->interactionConst_->epsilon_r,
gmxForceCalculator_->interactionConst_->epsilon_rf,
gmxForceCalculator_->interactionConst_->rcoulomb,
&gmxForceCalculator_->interactionConst_->k_rf,
gmxForceCalculator_->setParticlesOnGrid(particleInfoAllVdw_, coordinates, box);
}
- void NbvSetupUtil::constructPairList(const gmx::ListOfLists<int>& exclusions)
+ void NbvSetupUtil::constructPairList(ExclusionLists<int> exclusionLists)
{
- gmxForceCalculator_->nbv_->constructPairlist(gmx::InteractionLocality::Local, exclusions, 0,
- gmxForceCalculator_->nrnb_.get());
+ gmx::ListOfLists<int> exclusions(std::move(exclusionLists.ListRanges),
+ std::move(exclusionLists.ListElements));
+ gmxForceCalculator_->nbv_->constructPairlist(
+ gmx::InteractionLocality::Local, exclusions, 0, gmxForceCalculator_->nrnb_.get());
}
nbvSetupUtil.setupStepWorkload(options);
nbvSetupUtil.setupNbnxmInstance(system.topology().getParticleTypes().size(), options);
nbvSetupUtil.setParticlesOnGrid(system.coordinates(), system.box());
- nbvSetupUtil.constructPairList(system.topology().getGmxExclusions());
+ nbvSetupUtil.constructPairList(system.topology().exclusionLists());
nbvSetupUtil.setAtomProperties(system.topology().getParticleTypeIdOfAllParticles(),
system.topology().getCharges());
nbvSetupUtil.setupForceRec(system.box().legacyMatrix());
/*
* 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 "nblib/exception.h"
#include "nblib/interactions.h"
- #include "nblib/util/internal.h"
namespace nblib
{
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);
}
}
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);
}
}
if (nonbondedParameters_.count(interactionKey) == 0)
{
std::string message = formatString("Missing interaction between {} {}",
- particleTypeName1.value(), particleTypeName2.value());
+ particleTypeName1.value(),
+ particleTypeName2.value());
throw InputException(message);
}
}
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));
}
}
/*
* 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 Sebastian Keller <keller@cscs.ch>
*/
#include "nblib/listed_forces/bondtypes.h"
- #include "nblib/util/internal.h"
+ #include "nblib/util/util.hpp"
#include "testutils/testasserts.h"
{
template<class B>
- void testTwoParameterBondEquality(const B& deduceType)
+ void testTwoParameterBondEquality([[maybe_unused]] const B& deduceType)
{
- ignore_unused(deduceType);
B a(1, 2);
B b(1, 2);
EXPECT_TRUE(a == b);
}
template<class B>
- void testThreeParameterBondEquality(const B& deduceType)
+ void testThreeParameterBondEquality([[maybe_unused]] const B& deduceType)
{
- ignore_unused(deduceType);
B a(1, 2, 3);
B b(1, 2, 3);
EXPECT_TRUE(a == b);
}
template<class B>
- void testTwoParameterBondLessThan(const B& deduceType)
+ void testTwoParameterBondLessThan([[maybe_unused]] const B& deduceType)
{
- ignore_unused(deduceType);
B a(1, 2);
B b(1, 3);
EXPECT_TRUE(a < b);
}
template<class B>
- void testThreeParameterBondLessThan(const B& deduceType)
+ void testThreeParameterBondLessThan([[maybe_unused]] const B& deduceType)
{
- ignore_unused(deduceType);
B a(1, 2, 1);
B b(1, 3, 1);
EXPECT_TRUE(a < b);
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());
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());
/*
* 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.
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));
}
// one bond between atoms 0-1 with bond1 parameters and another between atoms 1-2 with bond2 parameters
std::vector<InteractionIndex<HarmonicBondType>> bondIndices{ { 0, 1, 0 }, { 1, 2, 1 } };
- DefaultAngle angle(Degrees(108.53), 397.5);
- std::vector<DefaultAngle> angles{ angle };
- std::vector<InteractionIndex<DefaultAngle>> angleIndices{ { 0, 1, 2, 0 } };
+ HarmonicAngleType angle(Degrees(108.53), 397.5);
+ std::vector<HarmonicAngleType> angles{ angle };
+ std::vector<InteractionIndex<HarmonicAngleType>> angleIndices{ { 0, 1, 2, 0 } };
pickType<HarmonicBondType>(interactions).indices = bondIndices;
pickType<HarmonicBondType>(interactions).parameters = bonds;
- pickType<DefaultAngle>(interactions).indices = angleIndices;
- pickType<DefaultAngle>(interactions).parameters = angles;
+ pickType<HarmonicAngleType>(interactions).indices = angleIndices;
+ pickType<HarmonicAngleType>(interactions).parameters = angles;
// initial position for the methanol atoms from the spc-water example
x = std::vector<gmx::RVec>{ { 1.97, 1.46, 1.209 }, { 1.978, 1.415, 1.082 }, { 1.905, 1.46, 1.03 } };
forces = std::vector<gmx::RVec>(3, gmx::RVec{ 0, 0, 0 });
- refBondForcesFloat =
- std::valarray<gmx::BasicVector<float>>{ { -22.8980637, 128.801575, 363.505951 },
- { -43.2698593, -88.0130997, -410.639252 },
- { 66.167923, -40.788475, 47.1333084 } };
- refAngleForcesFloat =
- std::valarray<gmx::BasicVector<float>>{ { 54.7276611, -40.1688995, 17.6805191 },
- { -81.8118973, 86.1988525, 60.1752243 },
- { 27.0842342, -46.0299492, -77.8557434 } };
-
- refBondForcesDouble = std::valarray<gmx::BasicVector<double>>{
- { -22.89764839974935, 128.79927224858977, 363.50016834602064 },
- { -43.24622441913251, -88.025652017772231, -410.61635172385434 },
- { 66.14387281888186, -40.773620230817542, 47.116183377833721 }
- };
- refAngleForcesDouble = std::valarray<gmx::BasicVector<double>>{
- { 54.726206806506234, -40.167809526198099, 17.680008528590257 },
- { -81.809781666748606, 86.196545126117257, 60.173723525141448 },
- { 27.083574860242372, -46.028735599919159, -77.853732053731704 }
- };
-
- refBondEnergyFloat = 0.2113433;
- refAngleEnergyFloat = 0.112774156;
-
- refBondEnergyDouble = 0.2113273434867636;
- refAngleEnergyDouble = 0.11276812148357591;
-
box.reset(new Box(3, 3, 3));
pbc.reset(new PbcHolder(*box));
}
std::shared_ptr<Box> box;
std::shared_ptr<PbcHolder> pbc;
+ };
- // reference values
- std::valarray<gmx::BasicVector<float>> refBondForcesFloat, refAngleForcesFloat;
- std::valarray<gmx::BasicVector<double>> refBondForcesDouble, refAngleForcesDouble;
+ TEST_F(ListedExampleData, ComputeHarmonicBondForces)
+ {
+ auto indices = pickType<HarmonicBondType>(interactions).indices;
+ auto bonds = pickType<HarmonicBondType>(interactions).parameters;
+ computeForces(indices, bonds, x, &forces, *pbc);
- float refBondEnergyFloat, refAngleEnergyFloat;
- double refBondEnergyDouble, refAngleEnergyDouble;
- };
+ Vector3DTest vector3DTest(1e-3);
+ vector3DTest.testVectors(forces, "Bond forces");
+ }
- TEST_F(ListedExampleData, DISABLED_ComputeHarmonicBondForces)
+ TEST_F(ListedExampleData, ComputeHarmonicBondEnergies)
{
auto indices = pickType<HarmonicBondType>(interactions).indices;
auto bonds = pickType<HarmonicBondType>(interactions).parameters;
real energy = computeForces(indices, bonds, x, &forces, *pbc);
- EXPECT_FLOAT_DOUBLE_EQ_TOL(energy,
- refBondEnergyFloat,
- refBondEnergyDouble,
- gmx::test::relativeToleranceAsFloatingPoint(refBondEnergyDouble, 1e-5));
-
- compareVectors(forces, refBondForcesFloat, refBondForcesDouble);
+ Vector3DTest vector3DTest(1e-4);
+ vector3DTest.testReal(energy, "Bond energy");
}
TEST_F(ListedExampleData, ComputeHarmonicAngleForces)
{
- auto indices = pickType<DefaultAngle>(interactions).indices;
- auto angles = pickType<DefaultAngle>(interactions).parameters;
- real energy = computeForces(indices, angles, x, &forces, *pbc);
+ auto indices = pickType<HarmonicAngleType>(interactions).indices;
+ auto angles = pickType<HarmonicAngleType>(interactions).parameters;
+ computeForces(indices, angles, x, &forces, *pbc);
+
+ Vector3DTest vector3DTest(1e-4);
+ vector3DTest.testVectors(forces, "Angle forces");
+ }
- EXPECT_FLOAT_DOUBLE_EQ_TOL(energy,
- refAngleEnergyFloat,
- refAngleEnergyDouble,
- gmx::test::relativeToleranceAsFloatingPoint(refAngleEnergyDouble, 1e-5));
+ TEST_F(ListedExampleData, CanReduceForces)
+ {
+ reduceListedForces(interactions, x, &forces, *pbc);
- compareVectors(forces, refAngleForcesFloat, refAngleForcesDouble);
+ Vector3DTest vector3DTest(1e-2);
+ vector3DTest.testVectors(forces, "Reduced forces");
}
- TEST_F(ListedExampleData, DISABLED_CanReduceForces)
+ TEST_F(ListedExampleData, CanReduceEnergies)
{
auto energies = reduceListedForces(interactions, x, &forces, *pbc);
real totalEnergy = std::accumulate(begin(energies), end(energies), 0.0);
- EXPECT_FLOAT_DOUBLE_EQ_TOL(totalEnergy,
- refBondEnergyFloat + refAngleEnergyFloat,
- refBondEnergyDouble + refAngleEnergyDouble,
- gmx::test::relativeToleranceAsFloatingPoint(refBondEnergyDouble, 1e-5));
-
- compareVectors(forces, refBondForcesFloat + refAngleForcesFloat, refBondForcesDouble + refAngleForcesDouble);
+ Vector3DTest vector3DTest(1e-4);
+ vector3DTest.testReal(totalEnergy, "Reduced energy");
}
{
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));
}
}
/*
* 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.
{
ListedInteractionData interactions;
- DefaultAngle angle(Degrees(1), 1);
- HarmonicBondType bond(1, 1);
+ HarmonicAngleType angle(Degrees(1), 1);
+ HarmonicBondType bond(1, 1);
int largestIndex = 20;
int nSplits = 3; // split ranges: [0,5], [6,11], [12, 19]
std::vector<InteractionIndex<HarmonicBondType>> bondIndices{
{ 0, 1, 0 }, { 0, 6, 0 }, { 11, 12, 0 }, { 18, 19, 0 }
};
- std::vector<InteractionIndex<DefaultAngle>> angleIndices{
+ std::vector<InteractionIndex<HarmonicAngleType>> angleIndices{
{ 0, 1, 2, 0 }, { 0, 6, 7, 0 }, { 11, 12, 13, 0 }, { 17, 19, 18, 0 }
};
- pickType<HarmonicBondType>(interactions).indices = bondIndices;
- pickType<DefaultAngle>(interactions).indices = angleIndices;
+ pickType<HarmonicBondType>(interactions).indices = bondIndices;
+ pickType<HarmonicAngleType>(interactions).indices = angleIndices;
std::vector<ListedInteractionData> splitInteractions =
splitListedWork(interactions, largestIndex, nSplits);
std::vector<InteractionIndex<HarmonicBondType>> refBondIndices0{ { 0, 1, 0 }, { 0, 6, 0 } };
- std::vector<InteractionIndex<DefaultAngle>> refAngleIndices0{ { 0, 1, 2, 0 }, { 0, 6, 7, 0 } };
- std::vector<InteractionIndex<HarmonicBondType>> refBondIndices1{ { 11, 12, 0 } };
- std::vector<InteractionIndex<DefaultAngle>> refAngleIndices1{ { 11, 12, 13, 0 } };
- std::vector<InteractionIndex<HarmonicBondType>> refBondIndices2{ { 18, 19, 0 } };
- std::vector<InteractionIndex<DefaultAngle>> refAngleIndices2{ { 17, 19, 18, 0 } };
+ std::vector<InteractionIndex<HarmonicAngleType>> refAngleIndices0{ { 0, 1, 2, 0 }, { 0, 6, 7, 0 } };
+ std::vector<InteractionIndex<HarmonicBondType>> refBondIndices1{ { 11, 12, 0 } };
+ std::vector<InteractionIndex<HarmonicAngleType>> refAngleIndices1{ { 11, 12, 13, 0 } };
+ std::vector<InteractionIndex<HarmonicBondType>> refBondIndices2{ { 18, 19, 0 } };
+ std::vector<InteractionIndex<HarmonicAngleType>> refAngleIndices2{ { 17, 19, 18, 0 } };
EXPECT_EQ(refBondIndices0, pickType<HarmonicBondType>(splitInteractions[0]).indices);
EXPECT_EQ(refBondIndices1, pickType<HarmonicBondType>(splitInteractions[1]).indices);
EXPECT_EQ(refBondIndices2, pickType<HarmonicBondType>(splitInteractions[2]).indices);
- EXPECT_EQ(refAngleIndices0, pickType<DefaultAngle>(splitInteractions[0]).indices);
- EXPECT_EQ(refAngleIndices1, pickType<DefaultAngle>(splitInteractions[1]).indices);
- EXPECT_EQ(refAngleIndices2, pickType<DefaultAngle>(splitInteractions[2]).indices);
+ EXPECT_EQ(refAngleIndices0, pickType<HarmonicAngleType>(splitInteractions[0]).indices);
+ EXPECT_EQ(refAngleIndices1, pickType<HarmonicAngleType>(splitInteractions[1]).indices);
+ EXPECT_EQ(refAngleIndices2, pickType<HarmonicAngleType>(splitInteractions[2]).indices);
}
{
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());
}
}
/*
* 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 "nblib/listed_forces/transformations.h"
- #include "nblib/util/internal.h"
+ #include "nblib/util/util.hpp"
namespace nblib
{
void sortInteractions(ListedInteractionData& interactions)
{
- auto sortKeyObj = [](const auto& lhs, const auto& rhs) { return interactionSortKey(lhs, rhs); };
- auto sortOneElement = [comparison = sortKeyObj](auto& interactionElement) {
- std::sort(begin(interactionElement.indices), end(interactionElement.indices), comparison);
+ auto sortOneElement = [](auto& interactionElement) {
+ 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>);
};
for_each_tuple(sortOneElement, interactions);
/*
* 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 "nblib/exception.h"
#include "nblib/molecules.h"
#include "nblib/particletype.h"
- #include "nblib/util/internal.h"
namespace nblib
{
-
Molecule::Molecule(MoleculeName moleculeName) : name_(std::move(moleculeName)) {}
MoleculeName Molecule::name() const
return *this;
}
- //! Two-particle interactions such as bonds and LJ1-4
- template<class Interaction>
- void Molecule::addInteraction(const ParticleName& particleNameI,
- const ResidueName& residueNameI,
- const ParticleName& particleNameJ,
- const ResidueName& residueNameJ,
- const Interaction& interaction)
+ ResidueName Molecule::residueName(const ParticleIdentifier& particleIdentifier)
+ {
+ return (particleIdentifier.residueName() == ResidueName{}) ? ResidueName(name_)
+ : particleIdentifier.residueName();
+ }
+
+ template<class ListedVariant, class... ParticleIdentifiers>
+ void Molecule::addInteractionImpl(const ListedVariant& interaction, const ParticleIdentifiers&... particles)
{
- if (particleNameI == particleNameJ and residueNameI == residueNameJ)
+ auto storeInteraction = [&](const auto& interaction_) {
+ using Interaction = std::decay_t<decltype(interaction_)>;
+
+ auto& interactionContainer = pickType<Interaction>(interactionData_);
+ interactionContainer.interactions_.emplace_back(particles...);
+ interactionContainer.interactionTypes_.push_back(interaction_);
+ };
+
+ // add the interaction to the correct location in interactionData_
+ std::visit(storeInteraction, interaction);
+ }
+
+ void Molecule::addInteraction(const ParticleIdentifier& particleI,
+ const ParticleIdentifier& particleJ,
+ const TwoCenterInteraction& interaction)
+ {
+ if (particleI == particleJ)
{
throw InputException(std::string("Cannot add interaction of particle ")
- + particleNameI.value() + " with itself in molecule " + name_.value());
+ + particleI.particleName().value() + " with itself in molecule "
+ + name_.value());
}
- auto& interactionContainer = pickType<Interaction>(interactionData_);
- interactionContainer.interactions_.emplace_back(particleNameI, residueNameI, particleNameJ, residueNameJ);
- interactionContainer.interactionTypes_.push_back(interaction);
- addInteractionImpl(interaction, particleI.particleName(), residueName(particleI),
- particleJ.particleName(), residueName(particleJ));
++ addInteractionImpl(interaction,
++ particleI.particleName(),
++ residueName(particleI),
++ particleJ.particleName(),
++ residueName(particleJ));
}
- //! \cond DO_NOT_DOCUMENT
- #define ADD_INTERACTION_INSTANTIATE_TEMPLATE(x) \
- template void Molecule::addInteraction(const ParticleName& particleNameI, \
- const ResidueName& residueNameI, \
- const ParticleName& particleNameJ, \
- const ResidueName& residueNameJ, \
- const x& interaction);
- MAP(ADD_INTERACTION_INSTANTIATE_TEMPLATE, SUPPORTED_TWO_CENTER_TYPES)
- #undef ADD_INTERACTION_INSTANTIATE_TEMPLATE
- //! \endcond
-
- // add interactions with default residue name
- template<class Interaction>
- void Molecule::addInteraction(const ParticleName& particleNameI,
- const ParticleName& particleNameJ,
- const Interaction& interaction)
+ void Molecule::addInteraction(const ParticleIdentifier& particleI,
+ const ParticleIdentifier& particleJ,
+ const ParticleIdentifier& particleK,
+ const ThreeCenterInteraction& interaction)
{
- addInteraction(particleNameI, ResidueName(name_), particleNameJ, ResidueName(name_), interaction);
+ if (particleI == particleJ and particleJ == particleK)
+ {
+ throw InputException(std::string("Cannot add interaction of particle ")
+ + particleI.particleName().value() + " with itself in molecule "
+ + 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));
}
- //! \cond DO_NOT_DOCUMENT
- #define ADD_INTERACTION_INSTANTIATE_TEMPLATE(x) \
- template void Molecule::addInteraction( \
- const ParticleName& particleNameI, const ParticleName& particleNameJ, const x& interaction);
- MAP(ADD_INTERACTION_INSTANTIATE_TEMPLATE, SUPPORTED_TWO_CENTER_TYPES)
- #undef ADD_INTERACTION_INSTANTIATE_TEMPLATE
-
- //! 3-particle interactions such as angles
- template<class Interaction>
- void Molecule::addInteraction(const ParticleName& particleNameI,
- const ResidueName& residueNameI,
- const ParticleName& particleNameJ,
- const ResidueName& residueNameJ,
- const ParticleName& particleNameK,
- const ResidueName& residueNameK,
- const Interaction& interaction)
+ void Molecule::addInteraction(const ParticleIdentifier& particleI,
+ const ParticleIdentifier& particleJ,
+ const ParticleIdentifier& particleK,
+ const ParticleIdentifier& particleL,
+ const FourCenterInteraction& interaction)
{
- if (particleNameI == particleNameJ and particleNameJ == particleNameK)
+ if (particleI == particleJ and particleJ == particleK and particleK == particleL)
{
throw InputException(std::string("Cannot add interaction of particle ")
- + particleNameI.value() + " with itself in molecule " + name_.value());
+ + particleI.particleName().value() + " with itself in molecule "
+ + name_.value());
}
- auto& interactionContainer = pickType<Interaction>(interactionData_);
- interactionContainer.interactions_.emplace_back(
- particleNameI, residueNameI, particleNameJ, residueNameJ, particleNameK, residueNameK);
- interactionContainer.interactionTypes_.push_back(interaction);
- 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));
}
- #define ADD_INTERACTION_INSTANTIATE_TEMPLATE(x) \
- template void Molecule::addInteraction(const ParticleName& particleNameI, \
- const ResidueName& residueNameI, \
- const ParticleName& particleNameJ, \
- const ResidueName& residueNameJ, \
- const ParticleName& particleNameK, \
- const ResidueName& residueNameK, \
- const x& interaction);
- MAP(ADD_INTERACTION_INSTANTIATE_TEMPLATE, SUPPORTED_THREE_CENTER_TYPES)
- #undef ADD_INTERACTION_INSTANTIATE_TEMPLATE
-
- template<class Interaction>
- void Molecule::addInteraction(const ParticleName& particleNameI,
- const ParticleName& particleNameJ,
- const ParticleName& particleNameK,
- const Interaction& interaction)
+ void Molecule::addInteraction(const ParticleIdentifier& particleI,
+ const ParticleIdentifier& particleJ,
+ const ParticleIdentifier& particleK,
+ const ParticleIdentifier& particleL,
+ const ParticleIdentifier& particleM,
+ const FiveCenterInteraction& interaction)
{
- addInteraction(particleNameI,
- ResidueName(name_),
- particleNameJ,
- ResidueName(name_),
- particleNameK,
- ResidueName(name_),
- interaction);
+ if (particleI == particleJ and particleJ == particleK and particleK == particleL and particleL == particleM)
+ {
+ throw InputException(std::string("Cannot add interaction of particle ")
+ + particleI.particleName().value() + " with itself in molecule "
+ + 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));
}
- #define ADD_INTERACTION_INSTANTIATE_TEMPLATE(x) \
- template void Molecule::addInteraction(const ParticleName& particleNameI, \
- const ParticleName& particleNameJ, \
- const ParticleName& particleNameK, \
- const x& interaction);
- MAP(ADD_INTERACTION_INSTANTIATE_TEMPLATE, SUPPORTED_THREE_CENTER_TYPES)
- #undef ADD_INTERACTION_INSTANTIATE_TEMPLATE
- //! \endcond
int Molecule::numParticlesInMolecule() const
{
return particles_.size();
}
- void Molecule::addExclusion(const int particleIndex, const int particleIndexToExclude)
+ void Molecule::addExclusion(const ParticleIdentifier& particle, const ParticleIdentifier& particleToExclude)
{
- // We do not need to add exclusion in case the particle indexes are the same
- // because self exclusion are added by addParticle
- if (particleIndex != particleIndexToExclude)
+ if (particle == particleToExclude)
{
- exclusions_.emplace_back(particleIndex, particleIndexToExclude);
- exclusions_.emplace_back(particleIndexToExclude, particleIndex);
+ return;
}
- }
- void Molecule::addExclusion(std::tuple<ParticleName, ResidueName> particle,
- std::tuple<ParticleName, ResidueName> particleToExclude)
- {
// duplication for the swapped pair happens in getExclusions()
- exclusionsByName_.emplace_back(std::make_tuple(std::get<0>(particle),
- std::get<1>(particle),
- std::get<0>(particleToExclude),
- std::get<1>(particleToExclude)));
- }
-
- void Molecule::addExclusion(const ParticleName& particleName, const ParticleName& particleNameToExclude)
- {
- addExclusion(std::make_tuple(particleName, ResidueName(name_)),
- std::make_tuple(particleNameToExclude, ResidueName(name_)));
- exclusionsByName_.emplace_back(std::make_tuple(particle.particleName(), residueName(particle),
++ exclusionsByName_.emplace_back(std::make_tuple(particle.particleName(),
++ residueName(particle),
+ particleToExclude.particleName(),
+ residueName(particleToExclude)));
}
const Molecule::InteractionTuple& Molecule::interactionData() 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)
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)
--- /dev/null
- printf("No particle %s in residue %s in molecule %s found\n", particleName.value().c_str(),
- residueName.value().c_str(), moleculeName.value().c_str());
+ /*
+ * 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 ParticleSequencer class
+ *
+ * \author Victor Holanda <victor.holanda@cscs.ch>
+ * \author Joe Jordan <ejjordan@kth.se>
+ * \author Prashanth Kanduri <kanduri@cscs.ch>
+ * \author Sebastian Keller <keller@cscs.ch>
+ * \author Artem Zhmurov <zhmurov@gmail.com>
+ */
+
+ #include <algorithm>
+
+ #include "nblib/exception.h"
+ #include "nblib/particlesequencer.h"
+
+ namespace nblib
+ {
+
+ int ParticleSequencer::operator()(const MoleculeName& moleculeName,
+ int moleculeNr,
+ const ResidueName& residueName,
+ const ParticleName& particleName) const
+ {
+ try
+ {
+ return data_.at(moleculeName).at(moleculeNr).at(residueName).at(particleName);
+ }
+ catch (const std::out_of_range& outOfRange)
+ {
+ // TODO: use string format function once we have it
+ if (moleculeName.value() == residueName.value())
+ {
- printf("No particle %s in molecule %s found\n", particleName.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(),
+ moleculeName.value().c_str());
+ }
+
+ throw InputException(outOfRange.what());
+ }
+ }
+
+ void ParticleSequencer::build(const std::vector<std::tuple<Molecule, int>>& moleculesList)
+ {
+ int currentID = 0;
+ for (const auto& molNumberTuple : moleculesList)
+ {
+ const Molecule& molecule = std::get<0>(molNumberTuple);
+ const size_t numMols = std::get<1>(molNumberTuple);
+
+ auto& moleculeMap = data_[molecule.name()];
+
+ for (size_t i = 0; i < numMols; ++i)
+ {
+ auto& moleculeNrMap = moleculeMap[i];
+ for (int j = 0; j < molecule.numParticlesInMolecule(); ++j)
+ {
+ moleculeNrMap[molecule.residueName(j)][molecule.particleName(j)] = currentID++;
+ }
+ }
+ }
+ }
+
+ } // namespace nblib
/*
* 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/utility/arrayref.h"
+
// The entire nblib public API can be included with a single header or individual components
// can be included via their respective headers.
#include "nblib/nblib.h"
- // User defined coordinates.
- std::vector<nblib::Vec3> coordinates = {
- { 0.794, 1.439, 0.610 }, { 1.397, 0.673, 1.916 }, { 0.659, 1.080, 0.573 },
- { 1.105, 0.090, 3.431 }, { 1.741, 1.291, 3.432 }, { 1.936, 1.441, 5.873 },
- { 0.960, 2.246, 1.659 }, { 0.382, 3.023, 2.793 }, { 0.053, 4.857, 4.242 },
- { 2.655, 5.057, 2.211 }, { 4.114, 0.737, 0.614 }, { 5.977, 5.104, 5.217 },
- };
-
- // User defined velocities.
- std::vector<nblib::Vec3> velocities = {
- { 0.0055, -0.1400, 0.2127 }, { 0.0930, -0.0160, -0.0086 }, { 0.1678, 0.2476, -0.0660 },
- { 0.1591, -0.0934, -0.0835 }, { -0.0317, 0.0573, 0.1453 }, { 0.0597, 0.0013, -0.0462 },
- { 0.0484, -0.0357, 0.0168 }, { 0.0530, 0.0295, -0.2694 }, { -0.0550, -0.0896, 0.0494 },
- { -0.0799, -0.2534, -0.0079 }, { 0.0436, -0.1557, 0.1849 }, { -0.0214, 0.0446, 0.0758 },
- };
-
- // Force buffer initialization for each particle.
- std::vector<nblib::Vec3> forces = {
- { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 },
- { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 },
- { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 },
- { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 },
- };
-
// Main function to write the MD program.
int main(); // Keep the compiler happy
// Add the argon particle to a molecule. The names are for bookkeeping and need not match.
argonMolecule.addParticle(nblib::ParticleName("Argon"), argonAtom);
// Define Lennard-Jones params for argon (parameters from gromos43A1).
- const nblib::C6 ArC6{ 0.0062647225 }; // C6 parameter
- const nblib::C12 ArC12{ 9.847044e-06 }; // C12 parameter
+ nblib::C6 ArC6{ 0.0062647225 }; // C6 parameter
+ nblib::C12 ArC12{ 9.847044e-06 }; // C12 parameter
// Holder for non-bonded interactions.
nblib::ParticleTypesInteractions interactions;
// Add non-bonded interactions for argon.
// The TopologyBuilder builds the Topology!
nblib::TopologyBuilder topologyBuilder;
// Number of Argon particles (molecules) in the system.
- const int numParticles = 12;
+ int numParticles = 12;
// Add the requested number of argon molecules to a topology.
topologyBuilder.addMolecule(argonMolecule, numParticles);
// Add the argon interactions to the topology.
nblib::Topology topology = topologyBuilder.buildTopology();
// The system needs a bounding box. Only cubic and rectangular boxes are supported.
nblib::Box box(6.05449);
+ // User defined coordinates.
+ std::vector<nblib::Vec3> coordinates = {
+ { 0.794, 1.439, 0.610 }, { 1.397, 0.673, 1.916 }, { 0.659, 1.080, 0.573 },
+ { 1.105, 0.090, 3.431 }, { 1.741, 1.291, 3.432 }, { 1.936, 1.441, 5.873 },
+ { 0.960, 2.246, 1.659 }, { 0.382, 3.023, 2.793 }, { 0.053, 4.857, 4.242 },
+ { 2.655, 5.057, 2.211 }, { 4.114, 0.737, 0.614 }, { 5.977, 5.104, 5.217 },
+ };
+ // User defined velocities.
+ std::vector<nblib::Vec3> velocities = {
+ { 0.0055, -0.1400, 0.2127 }, { 0.0930, -0.0160, -0.0086 }, { 0.1678, 0.2476, -0.0660 },
+ { 0.1591, -0.0934, -0.0835 }, { -0.0317, 0.0573, 0.1453 }, { 0.0597, 0.0013, -0.0462 },
+ { 0.0484, -0.0357, 0.0168 }, { 0.0530, 0.0295, -0.2694 }, { -0.0550, -0.0896, 0.0494 },
+ { -0.0799, -0.2534, -0.0079 }, { 0.0436, -0.1557, 0.1849 }, { -0.0214, 0.0446, 0.0758 },
+ };
+ // Force buffer initialization for each particle.
+ std::vector<nblib::Vec3> forces = {
+ { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 },
+ { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 },
+ { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 },
+ { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 },
+ };
// A simulation state contains all the molecular information about the system.
nblib::SimulationState simState(coordinates, velocities, forces, box, topology);
// Kernel options are flags needed for force calculation.
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;
}
--- /dev/null
- ListedForceCalculator listedForceCalculator(topology.getInteractionData(),
- topology.numParticles(), 4, box);
+ /*
+ * 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 tests that sample code can run
+ *
+ * \author Victor Holanda <victor.holanda@cscs.ch>
+ * \author Joe Jordan <ejjordan@kth.se>
+ * \author Prashanth Kanduri <kanduri@cscs.ch>
+ * \author Sebastian Keller <keller@cscs.ch>
+ */
+
+ #include <cstdio>
+
+ #include "gromacs/utility/arrayref.h"
+
+ // The entire nblib public API can be included with a single header or individual components
+ // can be included via their respective headers.
+ #include "nblib/nblib.h"
+
+ using namespace nblib;
+
+ // Main function to write the MD program.
+ int main(); // Keep the compiler happy
+
+ int main()
+ {
+ // Create the particles
+ ParticleType Ow(ParticleTypeName("Ow"), Mass(15.999));
+ ParticleType Hw(ParticleTypeName("Hw"), Mass(1.00784));
+ ParticleType Cm(ParticleTypeName("Cm"), Mass(12.0107));
+ ParticleType Hc(ParticleTypeName("Hc"), Mass(1.00784));
+
+ ParticleTypesInteractions interactions(CombinationRule::Geometric);
+
+ // Parameters from a GROMOS compatible force-field 2016H66
+ // add non-bonded interactions for the particle types
+ interactions.add(Ow.name(), C6(0.0026173456), C12(2.634129e-06));
+ interactions.add(Hw.name(), C6(0.0), C12(0.0));
+ interactions.add(Cm.name(), C6(0.01317904), C12(34.363044e-06));
+ interactions.add(Hc.name(), C6(8.464e-05), C12(15.129e-09));
+
+ Molecule water(MoleculeName("Water"));
+ Molecule methane(MoleculeName("Methane"));
+
+ water.addParticle(ParticleName("O"), Ow);
+ water.addParticle(ParticleName("H1"), Hw);
+ water.addParticle(ParticleName("H2"), Hw);
+
+ water.addExclusion(ParticleName("H1"), ParticleName("O"));
+ water.addExclusion(ParticleName("H2"), ParticleName("O"));
+
+ methane.addParticle(ParticleName("C"), Cm);
+ methane.addParticle(ParticleName("H1"), Hc);
+ methane.addParticle(ParticleName("H2"), Hc);
+ methane.addParticle(ParticleName("H3"), Hc);
+ methane.addParticle(ParticleName("H4"), Hc);
+
+ methane.addExclusion(ParticleName("H1"), ParticleName("C"));
+ methane.addExclusion(ParticleName("H2"), ParticleName("C"));
+ methane.addExclusion(ParticleName("H3"), ParticleName("C"));
+ methane.addExclusion(ParticleName("H4"), ParticleName("C"));
+
+ HarmonicBondType ohHarmonicBond(1, 1);
+ HarmonicBondType hcHarmonicBond(2, 1);
+
+ HarmonicAngleType hohAngle(Degrees(120), 1);
+ HarmonicAngleType hchAngle(Degrees(109.5), 1);
+
+ // add harmonic bonds for water
+ water.addInteraction(ParticleName("O"), ParticleName("H1"), ohHarmonicBond);
+ water.addInteraction(ParticleName("O"), ParticleName("H2"), ohHarmonicBond);
+
+ // add the angle for water
+ water.addInteraction(ParticleName("H1"), ParticleName("O"), ParticleName("H2"), hohAngle);
+
+ // add harmonic bonds for methane
+ methane.addInteraction(ParticleName("H1"), ParticleName("C"), hcHarmonicBond);
+ methane.addInteraction(ParticleName("H2"), ParticleName("C"), hcHarmonicBond);
+ methane.addInteraction(ParticleName("H3"), ParticleName("C"), hcHarmonicBond);
+ methane.addInteraction(ParticleName("H4"), ParticleName("C"), hcHarmonicBond);
+
+ // add the angles for methane
+ methane.addInteraction(ParticleName("H1"), ParticleName("C"), ParticleName("H2"), hchAngle);
+ methane.addInteraction(ParticleName("H1"), ParticleName("C"), ParticleName("H3"), hchAngle);
+ methane.addInteraction(ParticleName("H1"), ParticleName("C"), ParticleName("H4"), hchAngle);
+ methane.addInteraction(ParticleName("H2"), ParticleName("C"), ParticleName("H3"), hchAngle);
+ methane.addInteraction(ParticleName("H2"), ParticleName("C"), ParticleName("H4"), hchAngle);
+ methane.addInteraction(ParticleName("H3"), ParticleName("C"), ParticleName("H4"), hchAngle);
+
+ // Define a box for the simulation
+ Box box(6.05449);
+
+ // Define options for the non-bonded kernels
+ NBKernelOptions options;
+ // Use a simple cutoff rule for Coulomb
+ options.coulombType = nblib::CoulombType::Cutoff;
+ // Disable SIMD for this example
+ options.nbnxmSimd = SimdKernels::SimdNo;
+
+ TopologyBuilder topologyBuilder;
+
+ // add molecules
+ topologyBuilder.addMolecule(water, 2);
+ topologyBuilder.addMolecule(methane, 1);
+
+ // add non-bonded interaction map
+ topologyBuilder.addParticleTypesInteractions(interactions);
+
+ Topology topology = topologyBuilder.buildTopology();
+
+ // User defined coordinates.
+ std::vector<Vec3> coordinates = {
+ { 0.005, 0.600, 0.244 }, // Oxygen from water_1
+ { -0.017, 0.690, 0.270 }, // Hydrogen_1 from water_1
+ { 0.051, 0.610, 0.161 }, // Hydrogen_2 from water_1
+ { 0.155, 0.341, 0.735 }, // Oxygen from water_2
+ { 0.140, 0.284, 0.660 }, // Hydrogen_1 from water_2
+ { 0.081, 0.402, 0.734 }, // Hydrogen_2 from water_2
+ { -0.024, -0.222, -0.640 }, // Carbon from methane_1
+ { -0.083, -0.303, -0.646 }, // Hydrogen_1 from methane_1
+ { -0.080, -0.140, -0.642 }, // Hydrogen_2 from methane_1
+ { 0.040, -0.221, -0.716 }, // Hydrogen_3 from methane_1
+ { 0.027, -0.225, -0.553 } // Hydrogen_4 from methane_1
+ };
+
+ // User defined velocities.
+ std::vector<Vec3> velocities = {
+ { 0.1823, -0.4158, 0.487 }, // Oxygen from water_1
+ { -1.7457, -0.5883, -0.460 }, // Hydrogen_1 from water_1
+ { 2.5085, -0.1501, 1.762 }, // Hydrogen_2 from water_1
+ { 0.6282, 0.4390, 0.001 }, // Oxygen from water_2
+ { -0.3206, 0.0700, 0.4630 }, // Hydrogen_1 from water_2
+ { -0.1556, -0.4529, 1.440 }, // Hydrogen_2 from water_2
+ { 0.0, 0.0, 0.0 }, // Carbon from methane_1
+ { 0.0, 0.0, 0.0 }, // Hydrogen_1 from methane_1
+ { 0.0, 0.0, 0.0 }, // Hydrogen_2 from methane_1
+ { 0.0, 0.0, 0.0 }, // Hydrogen_3 from methane_1
+ { 0.0, 0.0, 0.0 }, // Hydrogen_4 from methane_1
+ };
+
+ // Force buffer initialization for each particle.
+ std::vector<Vec3> forces(topology.numParticles(), Vec3{ 0, 0, 0 });
+
+ SimulationState simulationState(coordinates, velocities, forces, box, topology);
+
+ // The non-bonded force calculator contains all the data needed to compute forces
+ ForceCalculator forceCalculator(simulationState, options);
+
+ // The listed force calculator is also initialized with the required arguments
- 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]);
++ 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
- integrator.integrate(1.0, simulationState.coordinates(), simulationState.velocities(),
- simulationState.forces());
++ 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;
+
+ for (auto i = 0; i < numSteps; i++)
+ {
+ zeroCartesianArray(simulationState.forces());
+
+ forceCalculator.compute(simulationState.coordinates(), simulationState.forces());
+
+ listedForceCalculator.compute(simulationState.coordinates(), simulationState.forces());
+
+ // Integrate with a time step of 1 fs, positions, velocities and 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]);
++ 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]);
+
+ return 0;
+ } // main
/*
* 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 "nblib/particletype.h"
#include "nblib/simulationstate.h"
#include "nblib/topology.h"
- #include "nblib/util/internal.h"
#include "testutils/testasserts.h"
topologyBuilder.addParticleTypesInteractions(interactions);
Topology topology = topologyBuilder.buildTopology();
- // Some random starting conditions
- std::vector<Vec3> x(numAtoms, { -9.0, 8.0, -7.0 });
- std::vector<Vec3> v(numAtoms, { 0.6, -0.5, 0.4 });
- // Constant force acting on the atom
+ std::vector<Vec3> x(numAtoms, { 0.0, 0.0, 0.0 });
+ std::vector<Vec3> v(numAtoms, { 0.0, 0.0, 0.0 });
std::vector<Vec3> f(numAtoms, { 1.0, 2.0, 0.0 });
Box box(100);
<< 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());
}
- integrator.integrate(
- dt, simulationState.coordinates(), simulationState.velocities(), simulationState.forces());
}
}
/*
* 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 "nblib/tests/testhelpers.h"
#include "nblib/tests/testsystems.h"
#include "nblib/topology.h"
+ #include "nblib/util/setup.h"
namespace nblib
{
gmx::ArrayRef<Vec3> forces(simState.forces());
ASSERT_NO_THROW(forceCalculator.compute(simState.coordinates(), forces));
- /* Use higher-than-usual tolerance for forces. Some of the particles in the test systems are
- * very close to each other, and, for example, the distance between the first two particles
- * is approx. 0.13 and already has relative uncertainty around 1e-6. */
- gmx::test::FloatingPointTolerance forceTolerance(1.0e-5, 1.0e-9, 1e-4, 1.0e-9, 1000, 1000, true);
-
- Vector3DTest forcesOutputTest(forceTolerance);
+ Vector3DTest forcesOutputTest(5e-5);
forcesOutputTest.testVectors(forces, "SPC-methanol forces");
}
{
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()));
}
}
/*
* 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.
HarmonicBondType ometBond(1.1, 1.2);
methanol_.addInteraction(ParticleName("O2"), ParticleName("Me1"), ometBond);
- DefaultAngle ochAngle(Degrees(108.52), 397.5);
+ HarmonicAngleType ochAngle(Degrees(108.52), 397.5);
methanol_.addInteraction(ParticleName("O2"), ParticleName("Me1"), ParticleName("H3"), ochAngle);
}
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
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
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"));
/*
* 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 <gtest/gtest.h>
#include "gromacs/topology/exclusionblocks.h"
+ #include "gromacs/utility/listoflists.h"
#include "nblib/exception.h"
#include "nblib/particletype.h"
+ #include "nblib/sequencing.hpp"
#include "nblib/tests/testsystems.h"
#include "nblib/topology.h"
+ #include "nblib/topologyhelpers.h"
+ #include "nblib/particlesequencer.h"
namespace nblib
{
TEST(NBlibTest, TopologyHasExclusions)
{
- WaterTopologyBuilder waters;
- Topology watersTopology = waters.buildTopology(2);
- const gmx::ListOfLists<int>& testExclusions = watersTopology.getGmxExclusions();
+ WaterTopologyBuilder waters;
+ Topology watersTopology = waters.buildTopology(2);
+ ExclusionLists<int> exclusionLists = watersTopology.exclusionLists();
+ const gmx::ListOfLists<int> testExclusions(std::move(exclusionLists.ListRanges),
+ std::move(exclusionLists.ListElements));
const std::vector<std::vector<int>>& refExclusions = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
{ 3, 4, 5 }, { 3, 4, 5 }, { 3, 4, 5 } };
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")));
}
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 =
std::vector<std::tuple<Molecule, int>> molecules{ std::make_tuple(water, 2),
std::make_tuple(methanol, 1) };
- detail::ParticleSequencer particleSequencer;
+ ParticleSequencer particleSequencer;
particleSequencer.build(molecules);
auto pairs = detail::sequenceIDs<HarmonicBondType>(molecules, particleSequencer);
std::vector<std::tuple<Molecule, int>> molecules{ std::make_tuple(water, 2),
std::make_tuple(methanol, 1) };
- detail::ParticleSequencer particleSequencer;
+ ParticleSequencer particleSequencer;
particleSequencer.build(molecules);
auto pairs = detail::sequenceIDs<HarmonicBondType>(molecules, particleSequencer);
#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)
Molecule water = WaterMoleculeBuilder{}.waterMolecule();
Molecule methanol = MethanolMoleculeBuilder{}.methanolMolecule();
- CubicBondType testBond(1., 1., 1.);
- DefaultAngle testAngle(Degrees(1), 1);
+ CubicBondType testBond(1., 1., 1.);
+ HarmonicAngleType testAngle(Degrees(1), 1);
water.addInteraction(ParticleName("H1"), ParticleName("H2"), testBond);
water.addInteraction(ParticleName("H1"), ParticleName("Oxygen"), ParticleName("H2"), testAngle);
auto interactionData = topology.getInteractionData();
auto& harmonicBonds = pickType<HarmonicBondType>(interactionData);
auto& cubicBonds = pickType<CubicBondType>(interactionData);
- auto& angleInteractions = pickType<DefaultAngle>(interactionData);
+ auto& angleInteractions = pickType<HarmonicAngleType>(interactionData);
HarmonicBondType ohBond(1., 1.);
HarmonicBondType ohBondMethanol(1.01, 1.02);
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);
- DefaultAngle methanolAngle(Degrees(108.52), 397.5);
- std::vector<DefaultAngle> angleReference{ testAngle, methanolAngle };
- std::vector<InteractionIndex<DefaultAngle>> angleIndicesReference{
+ HarmonicAngleType methanolAngle(Degrees(108.52), 397.5);
+ std::vector<HarmonicAngleType> angleReference{ testAngle, methanolAngle };
+ std::vector<InteractionIndex<HarmonicAngleType>> angleIndicesReference{
{ std::min(H1, H2), Ow, std::max(H1, H2), 0 }, { std::min(MeH1, MeO1), Me1, std::max(MeO1, MeH1), 1 }
};
EXPECT_EQ(angleReference, angleInteractions.parameters);
reference.push_back(localBlock);
reference.push_back(localBlock);
- std::vector<gmx::ExclusionBlock> probe = detail::toGmxExclusionBlock(testInput);
+ std::vector<gmx::ExclusionBlock> probe = toGmxExclusionBlock(testInput);
ASSERT_EQ(reference.size(), probe.size());
for (size_t i = 0; i < reference.size(); ++i)
/*
* 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 Sebastian Keller <keller@cscs.ch>
* \author Artem Zhmurov <zhmurov@gmail.com>
*/
+ #include <algorithm>
#include <numeric>
#include "gromacs/topology/exclusionblocks.h"
#include "gromacs/utility/smalloc.h"
#include "nblib/exception.h"
#include "nblib/particletype.h"
+ #include "nblib/sequencing.hpp"
#include "nblib/topology.h"
- #include "nblib/util/internal.h"
+ #include "nblib/util/util.hpp"
+ #include "nblib/topologyhelpers.h"
namespace nblib
{
TopologyBuilder::TopologyBuilder() : numParticles_(0) {}
- gmx::ListOfLists<int> TopologyBuilder::createExclusionsListOfLists() const
+ ExclusionLists<int> TopologyBuilder::createExclusionsLists() const
{
const auto& moleculesList = molecules_;
"No exclusions found in the " + molecule.name().value() + " molecule.";
assert((!exclusions.empty() && message.c_str()));
- std::vector<gmx::ExclusionBlock> exclusionBlockPerMolecule =
- detail::toGmxExclusionBlock(exclusions);
+ std::vector<gmx::ExclusionBlock> exclusionBlockPerMolecule = toGmxExclusionBlock(exclusions);
// duplicate the exclusionBlockPerMolecule for the number of Molecules of (numMols)
for (size_t i = 0; i < numMols; ++i)
{
- auto offsetExclusions =
- detail::offsetGmxBlock(exclusionBlockPerMolecule, particleNumberOffset);
+ 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();
exclusionsListOfListsGlobal.pushBack(block.atomNumber);
}
- return exclusionsListOfListsGlobal;
+ std::vector<int> listRanges(exclusionsListOfListsGlobal.listRangesView().begin(),
+ exclusionsListOfListsGlobal.listRangesView().end());
+ std::vector<int> listElements(exclusionsListOfListsGlobal.elementsView().begin(),
+ exclusionsListOfListsGlobal.elementsView().end());
+ ExclusionLists<int> exclusionListsGlobal;
+ exclusionListsGlobal.ListRanges = std::move(listRanges);
+ exclusionListsGlobal.ListElements = std::move(listElements);
+
+ return exclusionListsGlobal;
}
- ListedInteractionData TopologyBuilder::createInteractionData(const detail::ParticleSequencer& particleSequencer)
+ ListedInteractionData TopologyBuilder::createInteractionData(const ParticleSequencer& particleSequencer)
{
ListedInteractionData interactionData;
// 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
// 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 };
}
topology_.numParticles_ = numParticles_;
- topology_.exclusions_ = createExclusionsListOfLists();
- topology_.charges_ = extractParticleTypeQuantity<real>([](const auto& data, auto& map) {
- ignore_unused(map);
- return data.charge_;
- });
+ topology_.exclusionLists_ = createExclusionsLists();
+ topology_.charges_ = extractParticleTypeQuantity<real>(
+ [](const auto& data, [[maybe_unused]] auto& map) { return data.charge_; });
// map unique ParticleTypes to IDs
std::unordered_map<std::string, int> nameToId;
}
topology_.particleTypeIdOfAllParticles_ =
- extractParticleTypeQuantity<int>([&nameToId](const auto& data, auto& map) {
- ignore_unused(map);
+ extractParticleTypeQuantity<int>([&nameToId](const auto& data, [[maybe_unused]] auto& map) {
return nameToId[data.particleTypeName_];
});
- detail::ParticleSequencer particleSequencer;
+ ParticleSequencer particleSequencer;
particleSequencer.build(molecules_);
topology_.particleSequencer_ = std::move(particleSequencer);
{
std::string message =
formatString("Missing nonbonded interaction parameters for pair {} {}",
- particleType1.first, particleType2.first);
+ particleType1.first,
+ particleType2.first);
throw InputException(message);
}
}
return combinationRule_;
}
- gmx::ListOfLists<int> Topology::getGmxExclusions() const
+ ExclusionLists<int> Topology::exclusionLists() const
{
- return exclusions_;
+ return exclusionLists_;
}
} // namespace nblib
/*
* 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 Sebastian Keller <keller@cscs.ch>
* \author Artem Zhmurov <zhmurov@gmail.com>
*/
- #include <numeric>
+
+ #include <algorithm>
#include "gromacs/topology/exclusionblocks.h"
- #include "gromacs/utility/smalloc.h"
- #include "nblib/exception.h"
- #include "nblib/listed_forces/transformations.h"
#include "nblib/topologyhelpers.h"
- #include "nblib/util/internal.h"
namespace nblib
{
- namespace detail
- {
-
std::vector<gmx::ExclusionBlock> toGmxExclusionBlock(const std::vector<std::tuple<int, int>>& tupleList)
{
std::vector<gmx::ExclusionBlock> ret;
// 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;
}
- int ParticleSequencer::operator()(const MoleculeName& moleculeName,
- int moleculeNr,
- const ResidueName& residueName,
- const ParticleName& particleName) const
- {
- try
- {
- return data_.at(moleculeName).at(moleculeNr).at(residueName).at(particleName);
- }
- catch (const std::out_of_range& outOfRange)
- {
- // 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());
- }
- else
- {
- printf("No particle %s in molecule %s found\n",
- particleName.value().c_str(),
- moleculeName.value().c_str());
- }
-
- throw InputException(outOfRange.what());
- };
- }
-
- void ParticleSequencer::build(const std::vector<std::tuple<Molecule, int>>& moleculesList)
- {
- int currentID = 0;
- for (auto& molNumberTuple : moleculesList)
- {
- const Molecule& molecule = std::get<0>(molNumberTuple);
- const size_t numMols = std::get<1>(molNumberTuple);
-
- auto& moleculeMap = data_[molecule.name()];
-
- for (size_t i = 0; i < numMols; ++i)
- {
- auto& moleculeNrMap = moleculeMap[i];
- for (int j = 0; j < molecule.numParticlesInMolecule(); ++j)
- {
- moleculeNrMap[molecule.residueName(j)][molecule.particleName(j)] = currentID++;
- }
- }
- }
- }
-
- template<class I>
- std::tuple<std::vector<size_t>, std::vector<I>>
- collectInteractions(const std::vector<std::tuple<Molecule, int>>& molecules)
- {
- std::vector<I> collectedBonds;
- std::vector<size_t> expansionArray;
- for (auto& molNumberTuple : molecules)
- {
- const Molecule& molecule = std::get<0>(molNumberTuple);
- size_t numMols = std::get<1>(molNumberTuple);
-
- auto& interactions = pickType<I>(molecule.interactionData()).interactionTypes_;
-
- std::vector<size_t> moleculeExpansion(interactions.size());
- // assign indices to the bonds in the current molecule, continue counting from
- // the number of bonds seen so far (=collectedBonds.size())
- std::iota(begin(moleculeExpansion), end(moleculeExpansion), collectedBonds.size());
-
- std::copy(begin(interactions), end(interactions), std::back_inserter(collectedBonds));
-
- for (size_t i = 0; i < numMols; ++i)
- {
- std::copy(begin(moleculeExpansion), end(moleculeExpansion), std::back_inserter(expansionArray));
- }
- }
- return std::make_tuple(expansionArray, collectedBonds);
- }
-
- /// \cond DO_NOT_DOCUMENT
- #define COLLECT_BONDS_INSTANTIATE_TEMPLATE(x) \
- template std::tuple<std::vector<size_t>, std::vector<x>> collectInteractions( \
- const std::vector<std::tuple<Molecule, int>>&);
- MAP(COLLECT_BONDS_INSTANTIATE_TEMPLATE, SUPPORTED_LISTED_TYPES)
- /// \endcond
-
- namespace sequence_detail
- {
-
- //! Helper function to convert a tuple of strings into a particle index sequence
- template<class Tuple, class F, class... Args, size_t... Is>
- auto stringsToIndices_impl(const Tuple& tuple, std::index_sequence<Is...> is, F&& f, Args... args)
- {
- // return std::make_tuple(f(args..., std::get<2 * Is + 1>(tuple), std::get<2 * Is>(tuple))...);
- ignore_unused(is);
- return std::array<int, sizeof...(Is)>{ f(
- args..., std::get<2 * Is + 1>(tuple), std::get<2 * Is>(tuple))... };
- }
-
- /*! \brief
- * This takes a tuple<(string, string) * nCenter> from molecule
- * where nCenter = 2 for bonds, 3 for angles and 4 for dihedrals
- * each (ResidueName, ParticleName)-pair is converted to a particle sequence index
- * by calling the supplied function object f, containing the particleSequencer at the call site
- * Therefore, the return type is tuple<int * nCenter>
- *
- */
- template<class Tuple, class F, class... Args>
- auto stringsToIndices(const Tuple& tuple, F&& f, Args... args)
- {
- auto is = std::make_index_sequence<std::tuple_size<Tuple>::value / 2>{};
- return stringsToIndices_impl(tuple, is, std::forward<F>(f), args...);
- }
-
- //! Tuple ordering for two center interactions
- [[maybe_unused]] static std::array<int, 2> nblibOrdering(const std::array<int, 2>& t)
- {
- // for bonds (two coordinate indices),
- // we choose to store the lower sequence ID first. this allows for better unit tests
- // that are agnostic to how the input was set up
- int id1 = std::min(std::get<0>(t), std::get<1>(t));
- int id2 = std::max(std::get<0>(t), std::get<1>(t));
-
- return std::array<int, 2>{ id1, id2 };
- }
-
- //! Tuple ordering for three center interactions
- [[maybe_unused]] static std::array<int, 3> nblibOrdering(const std::array<int, 3>& t)
- {
- // for angles (three coordinate indices),
- // we choose to store the two non-center coordinate indices sorted.
- // such that ret[0] < ret[2] always (ret = returned tuple)
- int id1 = std::min(std::get<0>(t), std::get<2>(t));
- int id3 = std::max(std::get<0>(t), std::get<2>(t));
-
- return std::array<int, 3>{ id1, std::get<1>(t), id3 };
- }
-
- //! Tuple ordering for four center interactions
- [[maybe_unused]] static std::array<int, 4> nblibOrdering(const std::array<int, 4>& t)
- {
- return t;
- }
-
- //! Tuple ordering for five center interactions
- [[maybe_unused]] static std::array<int, 5> nblibOrdering(const std::array<int, 5>& t)
- {
- return t;
- }
-
- } // namespace sequence_detail
-
- //! For each interaction, translate particle identifiers (moleculeName, nr, residueName,
- //! particleName) to particle coordinate indices
- template<class B>
- std::vector<CoordinateIndex<B>> sequenceIDs(const std::vector<std::tuple<Molecule, int>>& molecules,
- const detail::ParticleSequencer& particleSequencer)
- {
- std::vector<CoordinateIndex<B>> coordinateIndices;
-
- auto callSequencer = [&particleSequencer](const MoleculeName& moleculeName,
- int i,
- const ResidueName& residueName,
- const ParticleName& particleName) {
- return particleSequencer(moleculeName, i, residueName, particleName);
- };
-
- // loop over all molecules
- for (const auto& molNumberTuple : molecules)
- {
- const Molecule& molecule = std::get<0>(molNumberTuple);
- size_t numMols = std::get<1>(molNumberTuple);
-
- for (size_t i = 0; i < numMols; ++i)
- {
- auto& interactions = pickType<B>(molecule.interactionData()).interactions_;
- for (const auto& interactionString : interactions)
- {
- CoordinateIndex<B> index = sequence_detail::stringsToIndices(
- interactionString, callSequencer, molecule.name(), i);
- coordinateIndices.push_back(nblibOrdering(index));
- }
- }
- }
- return coordinateIndices;
- }
-
- /// \cond DO_NOT_DOCUMENT
- #define SEQUENCE_PAIR_ID_INSTANTIATE_TEMPLATE(x) \
- template std::vector<CoordinateIndex<x>> sequenceIDs<x>( \
- const std::vector<std::tuple<Molecule, int>>&, const detail::ParticleSequencer&);
- MAP(SEQUENCE_PAIR_ID_INSTANTIATE_TEMPLATE, SUPPORTED_LISTED_TYPES)
- #undef SEQUENCE_PAIR_ID_INSTANTIATE_TEMPLATE
- /// \endcond
-
- template<class I>
- std::tuple<std::vector<size_t>, std::vector<I>> eliminateDuplicateInteractions(const std::vector<I>& aggregatedInteractions)
- {
- std::vector<size_t> uniqueIndices(aggregatedInteractions.size());
- std::vector<I> uniquInteractionsInstances;
- // if there are no interactions of type B we're done now
- if (aggregatedInteractions.empty())
- {
- return std::make_tuple(uniqueIndices, uniquInteractionsInstances);
- }
-
- // create 0,1,2,... sequence
- std::iota(begin(uniqueIndices), end(uniqueIndices), 0);
-
- std::vector<std::tuple<I, size_t>> enumeratedBonds(aggregatedInteractions.size());
- // append each interaction with its index
- std::transform(begin(aggregatedInteractions),
- end(aggregatedInteractions),
- begin(uniqueIndices),
- begin(enumeratedBonds),
- [](I b, size_t i) { return std::make_tuple(b, i); });
-
- auto sortKey = [](const auto& t1, const auto& t2) { return std::get<0>(t1) < std::get<0>(t2); };
- // sort w.r.t bonds. the result will contain contiguous segments of identical bond instances
- // the associated int indicates the original index of each BondType instance in the input vector
- std::sort(begin(enumeratedBonds), end(enumeratedBonds), sortKey);
-
- // initialize it1 and it2 to delimit first range of equal BondType instances
- auto range = std::equal_range(begin(enumeratedBonds), end(enumeratedBonds), enumeratedBonds[0], sortKey);
- auto it1 = range.first;
- auto it2 = range.second;
-
- // number of unique instances of BondType B = number of contiguous segments in enumeratedBonds =
- // number of iterations in the outer while loop below
- while (it1 != end(enumeratedBonds))
- {
- uniquInteractionsInstances.push_back(std::get<0>(*it1));
-
- // loop over all identical BondType instances;
- for (; it1 != it2; ++it1)
- {
- // we note down that the BondType instance at index <interactionIndex>
- // can be found in the uniqueBondInstances container at index <uniqueBondInstances.size()>
- int interactionIndex = std::get<1>(*it1);
- uniqueIndices[interactionIndex] = uniquInteractionsInstances.size() - 1;
- }
-
- // Note it1 has been incremented and is now equal to it2
- if (it1 != end(enumeratedBonds))
- {
- it2 = std::upper_bound(it1, end(enumeratedBonds), *it1, sortKey);
- }
- }
-
- return make_tuple(uniqueIndices, uniquInteractionsInstances);
- }
-
- /// \cond DO_NOT_DOCUMENT
- #define ELIMINATE_DUPLICATE_BONDS_INSTANTIATE_TEMPLATE(x) \
- template std::tuple<std::vector<size_t>, std::vector<x>> eliminateDuplicateInteractions( \
- const std::vector<x>& aggregatedBonds);
- MAP(ELIMINATE_DUPLICATE_BONDS_INSTANTIATE_TEMPLATE, SUPPORTED_LISTED_TYPES)
- #undef ELIMINATE_DUPLICATE_BONDS_INSTANTIATE_TEMPLATE
- /// \endcond
-
- } // namespace detail
-
} // namespace nblib
/*
* 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 Artem Zhmurov <zhmurov@gmail.com>
*/
- #include "nblib/util/internal.h"
- #include "nblib/util/user.h"
+ #include "nblib/util/setup.h"
#include "gromacs/random/tabulatednormaldistribution.h"
#include "gromacs/random/threefry.h"
#include "gromacs/utility/arrayref.h"
namespace nblib
{
- namespace detail
- {
-
- std::string next_token(std::string& s, const std::string& delimiter)
- {
- std::string token = s.substr(0, s.find(delimiter));
-
- std::size_t next = s.find(delimiter);
- if (next == std::string::npos)
- s.clear();
- else
- s.erase(0, next + delimiter.length());
-
- return token;
- }
-
- } // namespace detail
-
//! Generates an array of particle velocities based on the Maxwell-Boltzmann distribution
//! using temperature, masses and a random number generator
static std::vector<Vec3> low_mspeed(real tempi, std::vector<real> const& masses, gmx::ThreeFry2x64<>* rng)
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;
# 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.
# 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 1)
+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
# 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)
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
# naming affects the md5sum that has to go here, and if it isn't right
# release workflow will report a failure.
- set(REGRESSIONTEST_MD5SUM "ca12c40c20575df76b1b8b1a351cb7b0" CACHE INTERNAL "MD5 sum of the regressiontests tarball for this GROMACS version")
+ set(REGRESSIONTEST_MD5SUM "c9b6b2f0754b113efc44c738897a26f7" CACHE INTERNAL "MD5 sum of the regressiontests tarball for this GROMACS version")
math(EXPR GMX_VERSION_NUMERIC
"${GMX_VERSION_MAJOR}*10000 + ${GMX_VERSION_PATCH}")
-D VERSION_CMAKEIN=${VERSION_INFO_CMAKEIN_FILE_PARTIAL}
-D VERSION_OUT=${VERSION_INFO_CMAKE_FILE}
-D VERSION_STRING_OF_FORK=${GMX_VERSION_STRING_OF_FORK}
+ -D SOURCE_IS_SOURCE_DISTRIBUTION=${SOURCE_IS_SOURCE_DISTRIBUTION}
-P ${CMAKE_CURRENT_LIST_DIR}/gmxGenerateVersionInfoWithoutGit.cmake
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Generating release version information")
# not been tampered with.
# Note: The RUN_ALWAYS here is to regenerate the hash file only, it does not
# mean that the target is run in all builds
- if (PYTHONINTERP_FOUND)
+ if (Python3_Interpreter_FOUND)
# We need the full path to the directories after passing it through
set(FULL_PATH_DIRECTORIES "")
foreach(DIR ${SET_OF_DIRECTORIES_TO_CHECKSUM})
else()
add_custom_target(reference_checksum
COMMAND ${CMAKE_COMMAND} -E echo
- "Can not checksum files without python being available"
+ "Can not checksum files without python3 being available"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Generating reference checksum of source files")
endif()
# 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.
reference-manual/references.rst
# PNG formated plot files that don't need to be converted into PNG
# for the web page.
- reference-manual/plots/peregrine.png
+ reference-manual/plots/GMX_logos/gmx_falcon_blue.png
reference-manual/plots/adress.png
reference-manual/plots/plotje.png
reference-manual/plots/xvgr.png
reference-manual/special/plots/equipotential.pdf
reference-manual/special/plots/field.pdf
reference-manual/special/plots/gaussians.pdf
+ reference-manual/special/plots/lambda-values.pdf
reference-manual/special/plots/pulldirrel.pdf
reference-manual/special/plots/pull.pdf
reference-manual/special/plots/pullref.pdf
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/2021/2021.1.rst
release-notes/2021/major/highlights.rst
release-notes/2021/major/features.rst
release-notes/2021/major/performance.rst
release-notes/2020/2020.3.rst
release-notes/2020/2020.4.rst
release-notes/2020/2020.5.rst
+ release-notes/2020/2020.6.rst
release-notes/2020/major/highlights.rst
release-notes/2020/major/features.rst
release-notes/2020/major/performance.rst
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.
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++98 `compiler`_ you wish to use (or the environment variable ``CXX``)
+ * ``-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``)
``-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 enviroment variables with
+ 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
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
~~~~~~~~~~~~~~~~~~~~~~~~
.. _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|
^^^^^^^^^^^^^^^^^^^^
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
-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
-.. _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.
Functionality deprecated in |Gromacs| 2021
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ``mdrun -deffnm`` to be removed
+ """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+ This functionality is convenient when running very simple simulations,
+ because it permits grouping of a set of files that then differ only
+ their suffix. However, it does not work in the wider case of an
+ ``mdrun`` module (or modules) writing multiple ``.xvg`` output
+ files. The resulting filenames collide. That, and its interaction with
+ checkpointing and appending, have led to quite a few bug reports.
+
+ Because users can use a folder to group files (a standard mechanism
+ that they understand from experience outside of |Gromacs|), we can
+ build and test better software for them if we remove the erstwhile
+ convenience of ``mdrun -deffnm``. Please update your workflows
+ accordingly.
+
+ :issue:`3818`
+
OpenCL to be removed as a GPU framework
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
:issue:`3818` Work is underway for ports to AMD and Intel GPUs, and it
:issue:`1354` This has been broken for many years, and will be removed
as nobody has been found with interest to fix it.
+ Reading .pdo files in ``gmx wham``
+ """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+ The pull code in |Gromacs| before version 4.0 wrote files in ``.pdo``
+ format. Analyses of such files are likely no longer relevant, and if
+ they are, using any older GROMACS version will work. ``gmx wham`` will be
+ simpler to maintain and extend if we no longer support reading
+ ``.pdo`` files.
+
Functionality deprecated in |Gromacs| 2020
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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::
+ Patch releases
+ ^^^^^^^^^^^^^^
+
+ .. toctree::
+ :maxdepth: 1
+
+ 2021/2021.1
+
+
+Major release
+^^^^^^^^^^^^^
+
+.. toctree::
+ :maxdepth: 1
+
+ 2022/major/highlights
+ 2022/major/features
+ 2022/major/performance
+ 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
^^^^^^^^^^^^^
2021/major/portability
2021/major/miscellaneous
+
+Older (unmaintained) |Gromacs| series
+-------------------------------------------------------
+
|Gromacs| 2020 series
---------------------
.. toctree::
:maxdepth: 1
+ 2020/2020.6
2020/2020.5
2020/2020.4
2020/2020.3
2019/major/portability
2019/major/miscellaneous
-Older (unmaintained) |Gromacs| series
--------------------------------------------------------
-
|Gromacs| 2018 series
---------------------
.. mdp:: mts-level2-forces
- (longrange-nonbonded nonbonded pair dihedral)
- A list of force groups that will be evaluated only every
+ (longrange-nonbonded)
+ A list of one or more force groups that will be evaluated only every
:mdp:`mts-level2-factor` steps. Supported entries are:
``longrange-nonbonded``, ``nonbonded``, ``pair``, ``dihedral``, ``angle``,
``pull`` and ``awh``. With ``pair`` the listed pair forces (such as 1-4)
are selected. With ``dihedral`` all dihedrals are selected, including cmap.
All other forces, including all restraints, are evaluated and
integrated every step. When PME or Ewald is used for electrostatics
- and/or LJ interactions, ``longrange-nonbonded`` has to be entered here.
- The default value should work well for most standard atomistic simulations
- and in particular for replacing virtual site treatment for increasing
- the time step.
+ and/or LJ interactions, ``longrange-nonbonded`` can not be omitted here.
.. mdp:: mts-level2-factor
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
#
# 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.
# TODO: Version management policy and procedures.
_major = 0
-_minor = 2
+_minor = 3
_micro = 0
- _suffix = 'b1'
+ _suffix = ''
# Reference https://www.python.org/dev/peps/pep-0440/
# and https://packaging.pypa.io/en/latest/version/
#
# 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.
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'],
/*
* 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, 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.
/* Need to temporarily exponentiate the log weights to sum over simulations */
for (size_t i = 0; i < buffer.size(); i++)
{
- buffer[i] = pointState[i].inTargetRegion() ? std::exp(-pointState[i].logPmfSum()) : 0;
+ buffer[i] = pointState[i].inTargetRegion() ? std::exp(pointState[i].logPmfSum()) : 0;
}
sumOverSimulations(gmx::ArrayRef<double>(buffer), commRecord, multiSimComm);
{
if (pointState[i].inTargetRegion())
{
- pointState[i].setLogPmfSum(-std::log(buffer[i] * normFac));
+ pointState[i].setLogPmfSum(std::log(buffer[i] * normFac));
}
}
}
/* 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);
}
}
"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());
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)
{
/* 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
{
/* 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.
{
sumOverSimulations(
gmx::arrayRefFromArray(checkDim[d].covered.data(), grid.axis(d).numPoints()),
- commRecord, multiSimComm);
+ commRecord,
+ multiSimComm);
}
}
}
/* 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
}
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)
/* 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 */
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
{
{
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);
}
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];
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);
}
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));
}
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));
}
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));
}
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));
}
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));
}
{
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));
}
/*
* 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, 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.
}
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);
}
}
}
if (fieldStrength != 0)
{
// TODO: Check parallellism
- for (index i = 0; i != ssize(f); ++i)
+ for (int i = 0; i < mdatoms.homenr; ++i)
{
// NOTE: Not correct with perturbed charges
f[i][m] += mdatoms.chargeA[i] * fieldStrength;
*
* 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.
"energy_delta_h_start_time",
"energy_delta_h_start_lambda" };
-static const char* ePullhNames[epullhNR] = { "pullhistory_numcoordinates", "pullhistory_numgroups",
+static const char* ePullhNames[epullhNR] = { "pullhistory_numcoordinates",
+ "pullhistory_numgroups",
"pullhistory_numvaluesinxsum",
"pullhistory_numvaluesinfsum" };
#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, entryName(part, ecpt), reinterpret_cast<const rvec*>(data.data()), nf / 3);
}
else
#endif
{
/* Note: With double precision code dumping a single precision rvec will produce float iso rvec print, but that's a minor annoyance */
- pr_fvec(list, 0, entryName(part, ecpt),
- reinterpret_cast<const float*>(data.data()), nf, TRUE);
+ pr_fvec(list, 0, entryName(part, ecpt), reinterpret_cast<const float*>(data.data()), nf, TRUE);
}
break;
case xdr_datatype_double:
#if GMX_DOUBLE
if (cptElementType == CptElementType::real3)
{
- pr_rvecs(list, 0, entryName(part, ecpt),
- reinterpret_cast<const rvec*>(data.data()), nf / 3);
+ pr_rvecs(list, 0, entryName(part, ecpt), reinterpret_cast<const rvec*>(data.data()), nf / 3);
}
else
#endif
{
/* Note: With single precision code dumping a double precision rvec will produce float iso rvec print, but that's a minor annoyance */
- pr_dvec(list, 0, entryName(part, ecpt),
- reinterpret_cast<const double*>(data.data()), nf, TRUE);
+ pr_dvec(list, 0, entryName(part, ecpt), reinterpret_cast<const double*>(data.data()), nf, TRUE);
}
break;
default: GMX_RELEASE_ASSERT(false, "Data type not implemented for listing");
{
gmx_fatal(FARGS,
"Count mismatch for state entry %s, code count is %d, file count is %d\n",
- entryName(part, ecpt), nval, numElemInTheFile);
+ entryName(part, ecpt),
+ nval,
+ numElemInTheFile);
}
}
else if (nptr != nullptr)
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],
+ 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]);
/* Matching int and real should never occur, but check anyhow */
if (xdrTypeInTheFile == xdr_datatype_int || xdrTypeInTheCode == xdr_datatype_int)
{
gmx_fatal(FARGS,
- "Type %s: incompatible checkpoint formats or corrupted checkpoint file.", buf);
+ "Type %s: incompatible checkpoint formats or corrupted checkpoint file.",
+ buf);
}
}
{
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;
static int
doVector(XDR* xd, StatePart part, int 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, part, 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)
{
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, part, ecpt, sflags, vector.size(), nullptr, &v_real, nullptr, list, CptElementType::real);
}
//! Convert from view of RVec to view of real.
// 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, part, ecpt, sflags, numReals, nullptr, nullptr, nullptr, list, CptElementType::real);
}
}
*/
static int do_cpte_reals(XDR* xd, StatePart part, int 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, part, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::real);
}
/* This function does the same as do_cpte_reals,
*/
static int do_cpte_n_reals(XDR* xd, StatePart part, int ecpt, int sflags, int* n, real** v, 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, part, ecpt, sflags, -1, n, v, nullptr, list, CptElementType::real);
}
static int do_cpte_real(XDR* xd, StatePart part, int ecpt, int sflags, real* r, FILE* list)
{
- return doVectorLow<real, std::allocator<real>>(xd, part, ecpt, sflags, 1, nullptr, &r, nullptr,
- list, CptElementType::real);
+ return doVectorLow<real, std::allocator<real>>(
+ xd, part, ecpt, sflags, 1, nullptr, &r, nullptr, list, CptElementType::real);
}
static int do_cpte_ints(XDR* xd, StatePart part, int ecpt, int sflags, int n, int** v, FILE* list)
{
- return doVectorLow<int, std::allocator<int>>(xd, part, ecpt, sflags, n, nullptr, v, nullptr,
- list, CptElementType::integer);
+ return doVectorLow<int, std::allocator<int>>(
+ xd, part, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::integer);
}
static int do_cpte_int(XDR* xd, StatePart part, int ecpt, int sflags, int* i, FILE* list)
static int do_cpte_doubles(XDR* xd, StatePart part, int 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, part, 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)
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, part, ecpt, sflags, DIM * DIM, nullptr, &vr, nullptr, nullptr, CptElementType::matrix3x3);
if (list && ret == 0)
{
}
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, part, ecpt, sflags, n, nullptr, &(v[i]), nullptr, nullptr, CptElementType::matrix3x3);
if (list && reti == 0)
{
sprintf(name, "%s[%d]", entryName(part, ecpt), i);
}
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",
+ entryName(part, ecpt),
+ n,
+ nf);
}
if (list || !(sflags & (1 << ecpt)))
{
}
}
}
- 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, part, ecpt, sflags, nf * DIM * DIM, nullptr, &vr, nullptr, nullptr, CptElementType::matrix3x3);
for (i = 0; i < nf; i++)
{
for (j = 0; j < DIM; j++)
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)
{
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)
{
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
{
{
case estLAMBDA:
ret = doRealArrayRef(
- xd, part, i, sflags,
+ xd,
+ part,
+ i,
+ sflags,
gmx::arrayRefFromArray<real>(state->lambda.data(), state->lambda.size()),
list);
break;
ret = do_cpte_real(xd, part, i, sflags, &state->hist.disre_initf, list);
break;
case estDISRE_RM3TAV:
- ret = do_cpte_n_reals(xd, part, i, sflags, &state->hist.ndisrepairs,
- &state->hist.disre_rm3tav, list);
+ ret = do_cpte_n_reals(
+ xd, part, i, sflags, &state->hist.ndisrepairs, &state->hist.disre_rm3tav, list);
break;
case estORIRE_INITF:
ret = do_cpte_real(xd, part, i, sflags, &state->hist.orire_initf, list);
break;
case estORIRE_DTAV:
- ret = do_cpte_n_reals(xd, part, i, sflags, &state->hist.norire_Dtav,
- &state->hist.orire_Dtav, list);
+ ret = do_cpte_n_reals(
+ xd, part, i, sflags, &state->hist.norire_Dtav, &state->hist.orire_Dtav, list);
break;
case estPULLCOMPREVSTEP:
ret = doVector<double>(xd, part, i, sflags, &state->pull_com_prev_step, 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[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);
}
return 0;
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;
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_step_err(xd, eawhh_names[i], &(state->numUpdates), list);
break;
case eawhhFORCECORRELATIONGRID:
- ret = do_cpt_correlation_grid(xd, bRead, fflags,
- &biasHistory->forceCorrelationGrid, list, i);
+ ret = do_cpt_correlation_grid(
+ xd, bRead, fflags, &biasHistory->forceCorrelationGrid, list, i);
break;
default: gmx_fatal(FARGS, "Unknown awh history entry %d\n", i);
}
{
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;
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)
+ || (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)
+ || (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))
{
{
const char msg_precision_difference[] =
"You are continuing a simulation with a different precision. Not matching\n"
- "single/double precision will lead to precision or performance loss.\n";
+ "mixed/double precision will lead to precision or performance loss.\n";
if (fplog)
{
fprintf(fplog, "%s\n", msg_precision_difference);
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);
}
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);
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 */
{
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();
{
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(),
+ StatePart::pullHistory,
+ nullptr);
if (ret)
{
cp_error();
"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();
{
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();
{
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();
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,
+ mdModulesNotifier,
+ modularSimulatorCheckpointData,
+ useModularSimulator);
}
if (PAR(cr))
{
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, StatePart::pullHistory, 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();
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, StatePart::pullHistory, 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)
/* This file is completely threadsafe - keep it that way! */
-#include "tpxio.h"
+#include "gromacs/fileio/tpxio.h"
#include <cstdio>
#include <cstdlib>
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
static const int tpx_version = tpxv_Count - 1;
- /* This number should only be increased when you edit the TOPOLOGY section
- * or the HEADER of the tpx format.
+ /*! \brief
+ * Enum keeping track of incompatible changes for older TPR versions.
+ *
+ * The enum should be updated with a new field when editing the TOPOLOGY
+ * or HEADER of the tpx format. In particular, updating ftupd or
+ * changing the fields of TprHeaderVersion often trigger such needs.
+ *
* This way we can maintain forward compatibility too for all analysis tools
* and/or external programs that only need to know the atom/residue names,
* charges, and bond connectivity.
*
* In particular, it must be increased when adding new elements to
* ftupd, so that old code can read new .tpr files.
- *
- * Updated for added field that contains the number of bytes of the tpr body, excluding the header.
*/
- static const int tpx_generation = 27;
+ enum class TpxGeneration : int
+ {
+ Initial = 26, //! First version is 26
+ AddSizeField, //! TPR header modified for writing as a block.
+ AddVSite1, //! ftupd changed to include VSite1 type.
+ Count //! Number of entries.
+ };
+
+ //! Value of Current TPR generation.
+ static const int tpx_generation = static_cast<int>(TpxGeneration::Count) - 1;
/* This number should be the most recent backwards incompatible version
* I.e., if this number is 9, we cannot read tpx version 9 with this code.
* obsolete t_interaction_function types. Any data read from such
* fields is discarded. Their names have _NOLONGERUSED appended to
* them to make things clear.
+ *
+ * When adding to or making breaking changes to reading this struct,
+ * update TpxGeneration.
*/
static const t_ftupd ftupd[] = {
{ 70, F_RESTRBONDS },
{
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);
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)
{
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);
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__);
}
}
}
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;
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
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);
}
}
}
|| ((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);
// 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();
* 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.
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,
+ 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, " %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,
+ " %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);
+ 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));
+ printf("<D> = %.4f Std. Dev. = %.4f Error = %.4f\n", Dav, std::sqrt(VarD), std::sqrt(VarD / curr->nmol));
if (fn_pdb && x)
{
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);
}
}
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);
+ natoms,
+ top->atoms.nr);
}
snew(x[prev], natoms);
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(),
+ 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());
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);
+ 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++)
fprintf(stderr,
"\nNo frame found need time tpdb = %g ps\n"
"Can not write %s\n\n",
- t_pdb, pdb_file);
+ t_pdb,
+ pdb_file);
}
i = top->atoms.nr;
top->atoms.nr = nat_trx;
{
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());
+ 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)
}
}
/* 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);
+ 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[])
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))
+ 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;
}
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);
+ 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);
* 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.
psr->ticklinewidth = get_ereal(&inp, "ticklinewidth", psr->linewidth, wi);
psr->zerolinewidth = get_ereal(&inp, "zerolinewidth", psr->ticklinewidth, wi);
psr->X.lineatzero = get_eenum(&inp, "x-lineat0value", colors);
- psr->X.major = get_ereal(&inp, "x-major", 1, wi);
- psr->X.minor = get_ereal(&inp, "x-minor", 1, wi);
+ psr->X.major = get_ereal(&inp, "x-major", -1, wi);
+ psr->X.minor = get_ereal(&inp, "x-minor", -1, wi);
psr->X.offset = get_ereal(&inp, "x-firstmajor", 0.0, wi);
psr->X.first = (get_eenum(&inp, "x-majorat0", gmx_bools) != 0);
psr->X.majorticklen = get_ereal(&inp, "x-majorticklen", 8.0, wi);
/* 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)
/* 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))
{
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);
}
}
{
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)
{
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)
{
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)
{
{
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");
"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++)
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);
}
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);
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++)
{
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)
{
{ 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;
}
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");
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);
* 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.
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" };
+ 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);
}
{
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;
}
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)
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" : ""));
}
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());
}
}
- void rename_bb(t_atoms* pdba, const char* oldnm, const char* newnm, bool bFullCompare, t_symtab* symtab)
+ /*! \brief Rename all residues named \c oldnm to \c newnm
+ *
+ * Search for residues for which the residue name from the input
+ * configuration file matches \c oldnm, and when found choose the rtp
+ * entry and name of \c newnm.
+ *
+ * \todo Refactor this function to accept a lambda that accepts i and
+ * numMatchesFound but always produces \c newnm. Then remove
+ * renameResiduesInteractively by calling this method with suitable
+ * lambdas that capture its parameter \c rr and ignores
+ * numMatchesFound. */
+ void renameResidue(const gmx::MDLogger& logger,
+ t_atoms* pdba,
+ const char* oldnm,
+ const char* newnm,
+ bool bFullCompare,
+ t_symtab* symtab)
{
- char* bbnm;
- int i;
-
- for (i = 0; (i < pdba->nres); i++)
+ int numMatchesFound = 0;
+ for (int i = 0; (i < pdba->nres); i++)
{
- /* We have not set the rtp name yes, use the residue name */
- bbnm = *pdba->resinfo[i].name;
- if ((bFullCompare && (gmx::equalCaseInsensitive(bbnm, oldnm)))
- || (!bFullCompare && strstr(bbnm, oldnm) != nullptr))
+ /* We have not set the rtp name yet, use the residue name */
+ const char* residueNameInInputConfiguration = *pdba->resinfo[i].name;
+ if ((bFullCompare && (gmx::equalCaseInsensitive(residueNameInInputConfiguration, oldnm)))
+ || (!bFullCompare && strstr(residueNameInInputConfiguration, oldnm) != nullptr))
{
- /* Change the rtp builing block name */
- pdba->resinfo[i].rtp = put_symtab(symtab, newnm);
+ /* Change the rtp building block name */
+ pdba->resinfo[i].rtp = put_symtab(symtab, newnm);
+ pdba->resinfo[i].name = pdba->resinfo[i].rtp;
+ numMatchesFound++;
}
}
- numMatchesFound, numMatchesFound > 1 ? "s" : "", oldnm, newnm);
+ if (numMatchesFound > 0)
+ {
+ GMX_LOG(logger.info)
+ .asParagraph()
+ .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);
+ }
}
- void rename_bbint(t_atoms* pdba,
- const char* oldnm,
- const char* gettp(int, gmx::ArrayRef<const RtpRename>),
- bool bFullCompare,
- t_symtab* symtab,
- gmx::ArrayRef<const RtpRename> rr)
+ /*! \brief Rename all residues named \c oldnm according to the user's
+ * interactive choice
+ *
+ * Search for residues for which the residue name from the input
+ * configuration file matches \c oldnm, and when found choose the rtp
+ * entry and name of the interactive choice from \c gettp.
+ *
+ * \todo Remove this function, per todo in \c renameResidue. */
+ void renameResidueInteractively(t_atoms* pdba,
+ const char* oldnm,
+ const char* gettp(int, gmx::ArrayRef<const RtpRename>),
+ bool bFullCompare,
+ t_symtab* symtab,
+ gmx::ArrayRef<const RtpRename> rr)
{
- int i;
- const char* ptr;
- char* bbnm;
-
- for (i = 0; i < pdba->nres; i++)
+ // Search for residues i for which the residue name from the input
+ // configuration file matches oldnm, so it can replaced by the rtp
+ // entry and name of newnm.
+ for (int i = 0; i < pdba->nres; i++)
{
/* We have not set the rtp name yet, use the residue name */
- bbnm = *pdba->resinfo[i].name;
- if ((bFullCompare && (strcmp(bbnm, oldnm) == 0)) || (!bFullCompare && strstr(bbnm, oldnm) != nullptr))
+ char* residueNameInInputConfiguration = *pdba->resinfo[i].name;
+ if ((bFullCompare && (strcmp(residueNameInInputConfiguration, oldnm) == 0))
+ || (!bFullCompare && strstr(residueNameInInputConfiguration, oldnm) != nullptr))
{
- ptr = gettp(i, rr);
- pdba->resinfo[i].rtp = put_symtab(symtab, ptr);
+ const char* interactiveRtpChoice = gettp(i, rr);
+ pdba->resinfo[i].rtp = put_symtab(symtab, interactiveRtpChoice);
+ pdba->resinfo[i].name = pdba->resinfo[i].rtp;
}
}
}
.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)
{
"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
{
"\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]))
return natom;
}
- void process_chain(t_atoms* pdba,
+ void process_chain(const gmx::MDLogger& logger,
+ t_atoms* pdba,
gmx::ArrayRef<gmx::RVec> x,
bool bTrpU,
bool bPheU,
/* Rename aromatics, lys, asp and histidine */
if (bTyrU)
{
- rename_bb(pdba, "TYR", "TYRU", false, symtab);
+ renameResidue(logger, pdba, "TYR", "TYRU", false, symtab);
}
if (bTrpU)
{
- rename_bb(pdba, "TRP", "TRPU", false, symtab);
+ renameResidue(logger, pdba, "TRP", "TRPU", false, symtab);
}
if (bPheU)
{
- rename_bb(pdba, "PHE", "PHEU", false, symtab);
+ renameResidue(logger, pdba, "PHE", "PHEU", false, symtab);
}
if (bLysMan)
{
- rename_bbint(pdba, "LYS", get_lystp, false, symtab, rr);
+ renameResidueInteractively(pdba, "LYS", get_lystp, false, symtab, rr);
}
if (bArgMan)
{
- rename_bbint(pdba, "ARG", get_argtp, false, symtab, rr);
+ renameResidueInteractively(pdba, "ARG", get_argtp, false, symtab, rr);
}
if (bGlnMan)
{
- rename_bbint(pdba, "GLN", get_glntp, false, symtab, rr);
+ renameResidueInteractively(pdba, "GLN", get_glntp, false, symtab, rr);
}
if (bAspMan)
{
- rename_bbint(pdba, "ASP", get_asptp, false, symtab, rr);
+ renameResidueInteractively(pdba, "ASP", get_asptp, false, symtab, rr);
}
else
{
- rename_bb(pdba, "ASPH", "ASP", false, symtab);
+ renameResidue(logger, pdba, "ASPH", "ASP", false, symtab);
}
if (bGluMan)
{
- rename_bbint(pdba, "GLU", get_glutp, false, symtab, rr);
+ renameResidueInteractively(pdba, "GLU", get_glutp, false, symtab, rr);
}
else
{
- rename_bb(pdba, "GLUH", "GLU", false, symtab);
+ renameResidue(logger, pdba, "GLUH", "GLU", false, symtab);
}
if (!bHisMan)
}
else
{
- rename_bbint(pdba, "HIS", get_histp, true, symtab, rr);
+ renameResidueInteractively(pdba, "HIS", get_histp, true, symtab, rr);
}
/* Initialize the rtp builing block names with the residue names
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"
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);
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
"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());
}
}
}
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"))
.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)
{
"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
{
"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)
.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)
{
"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)
{
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);
}
}
"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))
{
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
{
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
}
/* 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)
{
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)
{
"%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))
{
.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()
{
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);
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(pdba,
++ 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]);
{
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
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();
}
}
{
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();
}
}
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
.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);
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)
{
"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));
}
}
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++)
{
{
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);
{
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
#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/symtab.h"
#include "gromacs/topology/topology.h"
+ #include "gromacs/utility/arrayref.h"
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/fatalerror.h"
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 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];
char fep_lambda[efptNR][STRLEN];
char lambda_weights[STRLEN];
std::vector<std::string> pullGroupNames;
}
}
-static void checkMtsRequirement(const t_inputrec& ir, const char* param, const int nstValue, warninp_t wi)
-{
- 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)
- {
- 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());
- }
-}
-
-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,
set_warning_line(wi, mdparin, -1);
+ /* 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))
+ {
+ std::vector<std::string> errorMessages = gmx::checkMtsRequirements(*ir);
+
+ for (const auto& errorMessage : errorMessages)
+ {
+ warning_error(wi, errorMessage.c_str());
+ }
+ }
+
if (ir->coulombtype == eelRF_NEC_UNSUPPORTED)
{
sprintf(warn_buf, "%s electrostatics is no longer supported", eel_names[eelRF_NEC_UNSUPPORTED]);
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]);
+ evdw_names[ir->vdwtype],
+ evdw_names[evdwCUT],
+ eintmod_names[ir->vdw_modifier]);
warning_note(wi, warn_buf);
ir->vdwtype = evdwCUT;
}
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",
+ evdw_names[ir->vdwtype],
+ eintmod_names[ir->vdw_modifier]);
warning_error(wi, warn_buf);
}
}
if (EEL_USER(ir->coulombtype))
{
- sprintf(warn_buf, "Coulomb type %s is not supported with the verlet scheme",
+ sprintf(warn_buf,
+ "Coulomb type %s is not supported with the verlet scheme",
eel_names[ir->coulombtype]);
warning_error(wi, warn_buf);
}
"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]);
+ etcoupl_names[ir->etc],
+ ei_names[ir->eI],
+ ei_names[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]);
+ etcoupl_names[ir->etc],
+ ei_names[ir->eI]);
}
warning_note(wi, warn_buf);
}
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]);
+ ei_names[eiVVAK],
+ ei_names[eiMD],
+ ei_names[eiVV]);
warning_note(wi, warn_buf);
}
if (!EI_DYNAMICS(ir->eI))
{
sprintf(warn_buf,
"Setting pcoupl from '%s' to 'no'. Pressure coupling does not apply to %s.",
- epcoupl_names[ir->epc], ei_names[ir->eI]);
+ epcoupl_names[ir->epc],
+ ei_names[ir->eI]);
warning_note(wi, warn_buf);
}
ir->epc = epcNO;
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->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
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]);
+ 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,
"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);
}
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));
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));
}
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));
{
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]);
+ 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]);
CHECK((fep->all_lambda[j][i] < 0) || (fep->all_lambda[j][i] > 1));
}
}
"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[efptVDW][i],
+ fep->all_lambda[efptCOUL][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))));
"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);
}
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]);
+ expand->equil_n_at_lam,
+ elmceq_names[elmceqNUMATLAM]);
CHECK((expand->equil_n_at_lam > 0) && (expand->elmceq != elmceqNUMATLAM));
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]);
+ expand->equil_samples,
+ elmceq_names[elmceqSAMPLES]);
CHECK((expand->equil_samples > 0) && (expand->elmceq != elmceqSAMPLES));
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]);
+ expand->equil_steps,
+ elmceq_names[elmceqSTEPS]);
CHECK((expand->equil_steps > 0) && (expand->elmceq != elmceqSTEPS));
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]);
+ expand->equil_samples,
+ elmceq_names[elmceqWLDELTA]);
CHECK((expand->equil_wl_delta > 0) && (expand->elmceq != elmceqWLDELTA));
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]);
+ expand->equil_ratio,
+ elmceq_names[elmceqRATIO]);
CHECK((expand->equil_ratio > 0) && (expand->elmceq != elmceqRATIO));
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]);
+ expand->equil_n_at_lam,
+ elmceq_names[elmceqNUMATLAM]);
CHECK((expand->equil_n_at_lam <= 0) && (expand->elmceq == elmceqNUMATLAM));
sprintf(err_buf,
"weight-equil-number-samples (%d) must be a positive integer if "
"lmc-weights-equil=%s",
- expand->equil_samples, elmceq_names[elmceqSAMPLES]);
+ expand->equil_samples,
+ elmceq_names[elmceqSAMPLES]);
CHECK((expand->equil_samples <= 0) && (expand->elmceq == elmceqSAMPLES));
sprintf(err_buf,
"weight-equil-number-steps (%d) must be a positive integer if lmc-weights-equil=%s",
- expand->equil_steps, elmceq_names[elmceqSTEPS]);
+ expand->equil_steps,
+ elmceq_names[elmceqSTEPS]);
CHECK((expand->equil_steps <= 0) && (expand->elmceq == elmceqSTEPS));
- sprintf(err_buf, "weight-equil-wl-delta (%f) must be > 0 if lmc-weights-equil=%s",
- expand->equil_wl_delta, elmceq_names[elmceqWLDELTA]);
+ 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-count-ratio (%f) must be > 0 if lmc-weights-equil=%s",
- expand->equil_ratio, elmceq_names[elmceqRATIO]);
+ 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, "lmc-weights-equil=%s only possible when lmc-stats = %s or lmc-stats %s",
- elmceq_names[elmceqWLDELTA], elamstats_names[elamstatsWL], elamstats_names[elamstatsWWL]);
+ 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-repeats (%d) must be greater than 0", expand->lmc_repeats);
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));
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));
{
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);
}
}
}
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);
}
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);
}
"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());
+ eel_names[eelCUT],
+ eel_names[eelUSER],
+ c_pbcTypeNames[PbcType::No].c_str());
CHECK(((ir->coulombtype != eelCUT) && (ir->coulombtype != eelUSER))
|| (ir->pbcType != PbcType::No) || (ir->rcoulomb != 0.0) || (ir->rvdw != 0.0));
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.",
+ etcoupl_names[ir->etc],
+ ei_names[ir->eI]);
CHECK(!(EI_VV(ir->eI)));
if (ir->nstcomm > 0 && (ir->etc == etcANDERSEN))
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]);
+ ir->nstcomm,
+ etcoupl_names[ir->etc]);
CHECK(ir->nstcomm > 1 && (ir->etc == etcANDERSEN));
}
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));
+ ETCOUPLTYPE(ir->etc),
+ ETCOUPLTYPE(etcVRESCALE));
warning_note(wi, warn_buf);
}
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);
+ EPCOUPLTYPE(ir->epc),
+ ir->tau_p,
+ pcouple_min_integration_steps(ir->epc),
+ dt_pcoupl);
warning(wi, warn_buf);
}
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]);
+ eel_names[ir->coulombtype],
+ eel_names[eelRF_ZERO]);
warning(wi, warn_buf);
}
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",
+ sprintf(warn_buf,
+ "Using epsilon-rf = epsilon-r with %s does not make sense",
eel_names[ir->coulombtype]);
warning(wi, warn_buf);
}
"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->coulombtype == eelPMESWITCH || ir->coulombtype == eelPMEUSER
|| ir->coulombtype == eelPMEUSERSWITCH)
{
- sprintf(err_buf, "With coulombtype = %s, rcoulomb must be <= rlist",
- eel_names[ir->coulombtype]);
+ sprintf(err_buf, "With coulombtype = %s, rcoulomb must be <= rlist", eel_names[ir->coulombtype]);
CHECK(ir->rcoulomb > ir->rlist);
}
}
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",
+ eel_names[ir->coulombtype],
+ orderMin,
+ orderMax);
warning_error(wi, warn_buf);
}
}
{
if (ir->ewald_geometry == eewg3D)
{
- 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(),
+ eewg_names[eewg3DC]);
warning(wi, warn_buf);
}
/* This check avoids extra pbc coding for exclusion corrections */
}
if ((ir->ewald_geometry == eewg3DC) && (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",
+ eel_names[ir->coulombtype],
+ eewg_names[eewg3DC],
+ c_pbcTypeNames[PbcType::XY].c_str());
warning(wi, warn_buf);
}
if ((ir->epsilon_surface != 0) && EEL_FULL(ir->coulombtype))
"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->vdw_modifier == eintmodNONE || ir->vdw_modifier == eintmodPOTSHIFT))
{
- 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",
+ evdw_names[ir->vdwtype],
+ eintmod_names[eintmodPOTSHIFT],
+ eintmod_names[eintmodNONE]);
warning_error(wi, err_buf);
}
}
}
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.");
}
}
}
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],
+ efpt_names[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 */
}
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))
{
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;
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;
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");
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);
ir->useMts = (get_eeenum(&inp, "mts", yesno_names, wi) != 0);
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);
- ir->mtsLevels.resize(2);
- mtsOpts.level2Forces = setStringEntry(
- &inp, "mts-level2-forces", "longrange-nonbonded nonbonded pair dihedral");
++ 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");
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");
/* 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);
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]))
+ 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(
}
break;
default:
- gmx_fatal(FARGS, "Pressure coupling type %s not implemented yet",
+ gmx_fatal(FARGS,
+ "Pressure coupling type %s not implemented yet",
epcoupltype_names[ir->epct]);
}
}
}
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)
{
/* 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)
s);
}
+ static void atomGroupRangeValidation(int natoms, int groupIndex, const t_blocka& block)
+ {
+ /* Now go over the atoms in the group */
+ for (int j = block.index[groupIndex]; (j < block.index[groupIndex + 1]); j++)
+ {
+ int aj = block.a[j];
+
+ /* Range checking */
+ if ((aj < 0) || (aj >= natoms))
+ {
+ gmx_fatal(FARGS, "Invalid atom number %d in indexfile", aj + 1);
+ }
+ }
+ }
+
static void do_numbering(int natoms,
SimulationGroups* groups,
gmx::ArrayRef<std::string> groupsFromMdpFile,
{
unsigned short* cbuf;
AtomGroupIndices* grps = &(groups->groups[gtype]);
- int j, gid, aj, ognr, ntot = 0;
+ int ntot = 0;
const char* title;
char warn_buf[STRLEN];
for (int i = 0; i != groupsFromMdpFile.ssize(); ++i)
{
/* Lookup the group name in the block structure */
- gid = search_string(groupsFromMdpFile[i].c_str(), block->nr, gnames);
+ const int gid = search_string(groupsFromMdpFile[i].c_str(), block->nr, gnames);
if ((grptp != egrptpONE) || (i == 0))
{
grps->emplace_back(gid);
}
-
+ GMX_ASSERT(block, "Can't have a nullptr block");
+ atomGroupRangeValidation(natoms, gid, *block);
/* Now go over the atoms in the group */
- for (j = block->index[gid]; (j < block->index[gid + 1]); j++)
+ for (int j = block->index[gid]; (j < block->index[gid + 1]); j++)
{
-
- aj = block->a[j];
-
- /* Range checking */
- if ((aj < 0) || (aj >= natoms))
- {
- gmx_fatal(FARGS, "Invalid atom number %d in indexfile", aj + 1);
- }
+ const int aj = block->a[j];
/* Lookup up the old group number */
- ognr = cbuf[aj];
+ 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
{
warning_note(wi, warn_buf);
}
/* Assign all atoms currently unassigned to a rest group */
- for (j = 0; (j < natoms); j++)
+ for (int j = 0; (j < natoms); j++)
{
if (cbuf[j] == NOGID)
{
{
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);
/* Assign the rest name to all atoms not currently assigned to a group */
- for (j = 0; (j < natoms); j++)
+ for (int j = 0; (j < natoms); j++)
{
if (cbuf[j] == NOGID)
{
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]);
* 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)
{
}
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;
}
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])
{
{
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);
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 ? eSwapFixedGrp_names[ig] : "Swap",
+ swap->grp[ig].molname,
+ swapg->nat);
snew(swapg->ind, swapg->nat);
for (i = 0; i < swapg->nat; i++)
{
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++)
{
"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)
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);
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);
+ ETCOUPLTYPE(ir->etc),
+ tau_min,
+ nstcmin,
+ ir->nsttcouple * ir->delta_t);
warning(wi, warn_buf);
}
}
}
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
{
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;
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++)
{
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++;
if (ir->opts.annealing[i] != eannNO)
{
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]),
+ eann_names[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]);
}
j = ir->opts.anneal_npoints[i] - 1;
if (ir->opts.annealing[i] == eannSINGLE)
{
- 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)
{
if (ir->bPull)
{
- const int gid = search_string(inputrecStrings->pullGroupNames[i].c_str(),
- defaultIndexGroups->nr, gnames);
+ for (int i = 1; i < ir->pull->ngroup; i++)
+ {
++ 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);
+ }
+
process_pull_groups(ir->pull->group, inputrecStrings->pullGroupNames, defaultIndexGroups, gnames);
checkPullCoords(ir->pull->group, ir->pull->coord);
*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);
-
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);
}
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);
+ do_numbering(natoms,
+ groups,
+ vcmGroupNames,
+ defaultIndexGroups,
+ gnames,
+ SimulationAtomGroupType::MassCenterVelocityRemoval,
+ restnm,
+ vcmGroupNames.empty() ? egrptpALL_GENREST : egrptpPART,
+ bVerbose,
+ wi);
if (ir->comm_mode != ecmNO)
{
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);
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 */
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++)
{
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);
}
}
}
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;
}
{
bool bLBRulesPossible, bC6ParametersWorkWithGeometricRules, bC6ParametersWorkWithLBRules;
- check_combination_rule_differences(mtop, 0, &bC6ParametersWorkWithGeometricRules,
- &bC6ParametersWorkWithLBRules, &bLBRulesPossible);
+ check_combination_rule_differences(
+ mtop, 0, &bC6ParametersWorkWithGeometricRules, &bC6ParametersWorkWithLBRules, &bLBRulesPossible);
if (ir->ljpme_combination_rule == eljpmeLB)
{
if (!bC6ParametersWorkWithLBRules || !bLBRulesPossible)
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;
ivec AbsRef;
char warn_buf[STRLEN];
"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);
}
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);
}
"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,
+ etcoupl_names[ir->etc],
+ ir->nstcomm,
+ ir->opts.tau_t[i],
+ nsteps);
CHECK(nsteps % ir->nstcomm != 0);
}
}
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",
+ etcoupl_names[ir->etc],
+ epcoupl_names[ir->epc],
+ "tau-p",
+ ir->tau_p,
+ "tau-t",
tau_t_max);
warning(wi, message.c_str());
}
"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));
+ EELTYPE(ir->coulombtype),
+ EELTYPE(eelCUT));
warning(wi, err_buf);
}
}
"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
&& !gmx_within_tol(sys->ffparams.reppow, 12.0, 10 * GMX_DOUBLE_EPS))
{
gmx_fatal(FARGS,
"Can not have dynamic box while using pull geometry '%s' "
"(dim %c)",
- EPULLGEOM(ir->pull->coord[c].eGeom), 'x' + m);
+ EPULLGEOM(ir->pull->coord[c].eGeom),
+ 'x' + m);
}
}
}
* 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.
/* 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",
+ { "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" }
+ "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" }
};
int ifunc_index(Directive d, int type)
{
return F_BHAM;
}
+ case Directive::d_vsites1:
+ if (type == 1)
+ {
+ return F_VSITE1;
+ }
+ else
+ {
+ gmx_fatal(FARGS, "Invalid vsites1 type %d", type);
+ }
case Directive::d_vsites2:
switch (type)
{
// 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);
+ set_nec(&(necessary[Directive::d_vsites1]), Directive::d_atoms, Directive::d_none);
set_nec(&(necessary[Directive::d_vsites2]), Directive::d_atoms, Directive::d_none);
set_nec(&(necessary[Directive::d_vsites3]), Directive::d_atoms, Directive::d_none);
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);
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;
* 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.
if (((m <= 0.0) || (mB <= 0.0)) && ((pt == eptAtom) || (pt == eptNucleus)))
{
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))
"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; */
{
/* 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),
+ dir2str(newd));
/* d = Directive::d_invalid; */
}
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);
break;
case Directive::d_atomtypes:
- push_at(symtab, atypes, &bondAtomType, pline, nb_funct, &nbparam,
- bGenPairs ? &pair : nullptr, wi);
+ push_at(symtab,
+ atypes,
+ &bondAtomType,
+ pline,
+ nb_funct,
+ &nbparam,
+ bGenPairs ? &pair : nullptr,
+ wi);
break;
case Directive::d_bondtypes: // Intended to fall through
|| 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);
+ generate_nbparams(
+ *combination_rule, nb_funct, &(interactions[nb_funct]), atypes, wi);
ncopy = copy_nbparams(nbparam, nb_funct, &(interactions[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);
+ gen_pairs((interactions[nb_funct]),
+ &(interactions[F_LJ14]),
+ fudgeLJ,
+ *combination_rule);
ncopy = copy_nbparams(pair, 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? */
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:
case Directive::d_vsites2:
case Directive::d_vsites3:
case Directive::d_vsites4:
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(
.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)
{
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,
+ nb_funct,
+ &(interactions[nb_funct]),
+ wi);
}
stupid_fill_block(&mi0->mols, mi0->atoms.nr, TRUE);
mi0->bProcessed = TRUE;
}
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 */
}
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))
{
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);
+ 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))
{
/*
* 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.
cl::sycl::buffer<int, 1> buffer(numThreads);
queue.submit([&](cl::sycl::handler& cgh) {
auto d_buffer = buffer.get_access<cl::sycl::access::mode::discard_write>(cgh);
- cgh.parallel_for<class DummyKernel>(numThreads, [=](cl::sycl::id<1> threadId) {
+ cl::sycl::range<1> range{ numThreads };
+ cgh.parallel_for<class DummyKernel>(range, [=](cl::sycl::id<1> threadId) {
d_buffer[threadId] = threadId.get(0);
});
})
{
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;
}
deviceInfos[i]->syclDevice = syclDevice;
deviceInfos[i]->status = checkDevice(i, *deviceInfos[i]);
deviceInfos[i]->deviceVendor =
- getDeviceVendor(syclDevice.get_info<sycl::info::device::vendor>().c_str());
+ getDeviceVendor(syclDevice.get_info<cl::sycl::info::device::vendor>().c_str());
}
return deviceInfos;
}
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(),
/*
* 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.
// 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_);
kernelLaunchConfig_.gridSize[0] = (fTypeRangeEnd + c_threadsPerBlock) / c_threadsPerBlock;
kernelLaunchConfig_.gridSize[1] = 1;
kernelLaunchConfig_.gridSize[2] = 1;
+ kernelLaunchConfig_.sharedMemorySize =
+ SHIFTS * sizeof(float3) + (c_threadsPerBlock / warp_size) * 3 * sizeof(float);
}
GpuBonded::Impl::~Impl()
{
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();
/*
* 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.
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)
{
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;
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);
}
}
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)
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;
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.
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)
{
__global__ void exec_kernel_gpu(BondedCudaKernelParameters kernelParams)
{
assert(blockDim.y == 1 && blockDim.z == 1);
- const int tid = blockIdx.x * blockDim.x + threadIdx.x;
- float vtot_loc = 0;
- float vtotVdw_loc = 0;
- float vtotElec_loc = 0;
- __shared__ float3 sm_fShiftLoc[SHIFTS];
+ const int tid = blockIdx.x * blockDim.x + threadIdx.x;
+ float vtot_loc = 0;
+ float vtotVdw_loc = 0;
+ float vtotElec_loc = 0;
+
+ extern __shared__ char sm_dynamicShmem[];
+ char* sm_nextSlotPtr = sm_dynamicShmem;
+ float3* sm_fShiftLoc = (float3*)sm_nextSlotPtr;
+ sm_nextSlotPtr += SHIFTS * sizeof(float3);
if (calcVir)
{
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;
{
float* vtotVdw = kernelParams.d_vTot + F_LJ14;
float* vtotElec = kernelParams.d_vTot + F_COUL14;
- atomicAdd(kernelParams.d_vTot + fType, vtot_loc);
- atomicAdd(vtotVdw, vtotVdw_loc);
- atomicAdd(vtotElec, vtotElec_loc);
+
+ // Stage atomic accumulation through shared memory:
+ // each warp will accumulate its own partial sum
+ // and then a single thread per warp will accumulate this to the global sum
+
+ int numWarps = blockDim.x / warpSize;
+ int warpId = threadIdx.x / warpSize;
+
+ // Shared memory variables to hold block-local partial sum
+ float* sm_vTot = (float*)sm_nextSlotPtr;
+ sm_nextSlotPtr += numWarps * sizeof(float);
+ float* sm_vTotVdw = (float*)sm_nextSlotPtr;
+ sm_nextSlotPtr += numWarps * sizeof(float);
+ float* sm_vTotElec = (float*)sm_nextSlotPtr;
+
+ if (threadIdx.x % warpSize == 0)
+ {
+ // One thread per warp initializes to zero
+ sm_vTot[warpId] = 0.;
+ sm_vTotVdw[warpId] = 0.;
+ sm_vTotElec[warpId] = 0.;
+ }
+ __syncwarp(); // All threads in warp must wait for initialization
+
+ // Perform warp-local accumulation in shared memory
+ atomicAdd(sm_vTot + warpId, vtot_loc);
+ atomicAdd(sm_vTotVdw + warpId, vtotVdw_loc);
+ atomicAdd(sm_vTotElec + warpId, vtotElec_loc);
+
+ __syncwarp(); // Ensure all threads in warp have completed
+ if (threadIdx.x % warpSize == 0)
+ { // One thread per warp accumulates partial sum into global sum
+ atomicAdd(kernelParams.d_vTot + fType, sm_vTot[warpId]);
+ atomicAdd(vtotVdw, sm_vTotVdw[warpId]);
+ atomicAdd(vtotElec, sm_vTotElec[warpId]);
+ }
}
/* Accumulate shift vectors from shared memory to global memory on the first SHIFTS threads of the block. */
if (calcVir)
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);
* 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.
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[efptFTYPE],
+ &(dvdl[efptFTYPE]),
+ md,
+ fcd,
+ 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[efptFTYPE],
+ &(dvdl[efptFTYPE]),
+ md,
+ fcd,
+ global_atom_index,
+ flavor);
}
}
else
/* 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,
+ dvdl,
+ md,
+ fr,
+ havePerturbedInteractions,
+ stepWork,
+ grpp,
+ global_atom_index);
}
if (thread == 0)
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;
}
}
/* 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);
+ 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);
/* 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());
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.data(),
+ md,
+ fcd,
+ tempFlags,
+ global_atom_index);
epot[ftype] += v;
}
}
// Todo: replace all rvec use here with ArrayRefWithPadding
const rvec* x = as_rvec_array(coordinates.paddedArrayRef().data());
+ const bool calculateRestInteractions =
+ interactionSelection_.test(static_cast<int>(ListedForces::InteractionGroup::Rest));
+
t_pbc pbc_full; /* Full PBC is needed for position restraints */
- if (haveRestraints(*fcdata))
+ if (calculateRestInteractions && haveRestraints(*fcdata))
{
if (!idef.il[F_POSRES].empty() || !idef.il[F_FBPOSRES].empty())
{
if (fcdata->orires->nr > 0)
{
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,
+ 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);
}
- 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.
{
lam_i[j] = (i == 0 ? lambda[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);
+ 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);
const double dvdlSum = std::accumulate(std::begin(dvdl), std::end(dvdl), 0.);
std::fill(std::begin(dvdl), std::end(dvdl), 0.0);
/*
* 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.
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) {
- 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)
{
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)
{
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();
}
real referenceSquaredSum = 0;
//! The sum of the squared compared density voxel values
real comparisonSquaredSum = 0;
- //! The covariance of the refernce and the compared density
+ //! The covariance of the reference and the compared density
real covariance = 0;
};
class CrossCorrelationGradientAtVoxel
{
public:
- //! Set up the gradident calculation with pre-computed values
+ //! Set up the gradient calculation with pre-computed values
CrossCorrelationGradientAtVoxel(const CrossCorrelationEvaluationHelperValues& preComputed) :
prefactor_(evaluatePrefactor(preComputed.comparisonSquaredSum, preComputed.referenceSquaredSum)),
comparisonPrefactor_(preComputed.covariance / preComputed.comparisonSquaredSum),
// To avoid numerical instability due to large squared density value sums
// division is re-written to avoid multiplying two large numbers
- // as product of two seperate divisions of smaller numbers
+ // as product of two separate divisions of smaller numbers
const real covarianceSqrt = sqrt(fabs(helperValues.covariance));
const int sign = helperValues.covariance > 0 ? 1 : -1;
return sign * (covarianceSqrt / sqrt(helperValues.referenceSquaredSum))
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();
}
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 };
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);
+ nosehoover_tcoupl(&(inputrec->opts),
+ ekind,
+ dttc,
+ state->nosehoover_xi.data(),
+ state->nosehoover_vxi.data(),
+ MassQ);
break;
case etcVRESCALE:
vrescale_tcoupl(inputrec, step, ekind, dttc, state->therm_integral.data());
{
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);
}
}
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<epcBERENDSEN>(fplog,
+ step,
+ inputrec,
+ dtpc,
+ pressure,
+ state->box,
+ forceVirial,
+ constraintVirial,
+ pressureCouplingMu,
+ &state->baros_integral);
+ pressureCouplingScaleBoxAndCoordinates<epcBERENDSEN>(inputrec,
+ pressureCouplingMu,
+ state->box,
+ state->box_rel,
+ start,
+ homenr,
+ state->x.rvec_array(),
+ nullptr,
+ md->cFREEZE,
+ nrnb,
+ scaleCoordinates);
}
break;
case (epcCRESCALE):
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<epcCRESCALE>(fplog,
+ step,
+ inputrec,
+ dtpc,
+ pressure,
+ state->box,
+ forceVirial,
+ constraintVirial,
+ pressureCouplingMu,
+ &state->baros_integral);
+ pressureCouplingScaleBoxAndCoordinates<epcCRESCALE>(inputrec,
+ pressureCouplingMu,
+ state->box,
+ state->box_rel,
+ start,
+ homenr,
+ state->x.rvec_array(),
+ state->v.rvec_array(),
+ md->cFREEZE,
+ nrnb,
+ scaleCoordinates);
}
break;
case (epcPARRINELLORAHMAN):
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)))
{
- andersen_tcoupl(ir, step, cr, md, v, rate, upd->getAndersenRandomizeGroup(),
- upd->getBoltzmanFactor());
+ andersen_tcoupl(
+ ir, step, cr, md, v, rate, upd->getAndersenRandomizeGroup(), upd->getBoltzmanFactor());
return TRUE;
}
return FALSE;
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<int 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<int 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;
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<epcBERENDSEN>(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:
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:
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:
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;
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",
+ 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);
- }
}
-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<epcCRESCALE>(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);
{
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] * BOLTZ;
if (kt < 0.0)
{
kt = 0.0;
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 * PRESFAC / vol) * gauss / DIM);
}
break;
case epctSEMIISOTROPIC:
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 * 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 * PRESFAC / vol / DIM) * gauss2);
}
break;
case epctSURFACETENSION:
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 * 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 * PRESFAC / vol) * gauss2);
}
break;
default:
- gmx_fatal(FARGS, "C-rescale pressure coupling type %s not supported yet\n",
+ gmx_fatal(FARGS,
+ "C-rescale pressure coupling type %s not supported yet\n",
EPCOUPLTYPETYPE(ir->epct));
}
- /* To fullfill the orientation restrictions on triclinic boxes
+}
+
+template<int 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 == epcBERENDSEN || pressureCouplingType == epcCRESCALE,
+ "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.
*/
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);
}
}
-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<int pressureCouplingType>
+void pressureCouplingScaleBoxAndCoordinates(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)
{
- 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);
+ static_assert(pressureCouplingType == epcBERENDSEN || pressureCouplingType == epcCRESCALE,
+ "pressureCouplingScaleBoxAndCoordinates is only implemented for Berendsen and "
+ "C-rescale pressure coupling");
- /* Scale the positions and the velocities */
- if (scaleCoordinates)
+ ivec* nFreeze = ir->opts.nFreeze;
+ matrix inv_mu;
+ if (pressureCouplingType == epcCRESCALE)
{
-#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;
-
- 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];
- }
- }
+ gmx::invertBoxMatrix(mu, inv_mu);
}
- /* compute final boxlengths */
- 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];
- box[d][ZZ] = mu[ZZ][ZZ] * box[d][ZZ];
- }
-
- 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(emntUpdate);
+#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 != nullptr)
{
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];
+ if (pressureCouplingType == epcCRESCALE)
+ {
+ 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 == epcCRESCALE)
+ {
+ 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 == epcCRESCALE)
+ {
+ 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];
{
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 == eiVV));
/* need to rescale the kinetic energies and velocities here. Could
scale the velocities later, but we need them scaled in order to
produce the correct outputs, so we'll scale them here. */
if (EI_VV(ir->eI) && (ir->epc == epcMTTK) && (ir->etc != etcNOSEHOOVER))
{
- 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);
const double* ivxi = &state->nosehoover_vxi[i * nh];
const double* iQinv = &(MassQ->Qinv[i * nh]);
- int nd = static_cast<int>(ir->opts.nrdf[i]);
+ real nd = ir->opts.nrdf[i];
real reft = std::max<real>(ir->opts.ref_t[i], 0);
real kT = BOLTZ * reft;
{
energy += 0.5 * gmx::square(ivxi[j]) / iQinv[j];
/* contribution from the thermal variable of the NH chain */
- int ndj;
+ real ndj = 0;
if (j == 0)
{
ndj = nd;
}
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]);
}
}
}
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
void rescale_velocities(const gmx_ekindata_t* ekind, const t_mdatoms* mdatoms, int start, int end, rvec v[])
{
- unsigned short *cACC, *cTC;
- int ga, gt, n, d;
- real lg;
- rvec vrel;
-
- cTC = mdatoms->cTC;
-
+ const unsigned short* 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)
{
- 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;
}
}
}
break;
case eannSINGLE: 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.
#include "gromacs/utility/gmxmpi.h"
#include "gromacs/utility/smalloc.h"
+ #include "expanded_internal.h"
+
static void init_df_history_weights(df_history_t* dfhist, const t_expanded* expand, int nlim)
{
int i;
int64_t step)
{
gmx_bool bSufficientSamples;
+ real acceptanceWeight;
int i;
- int n0, np1, nm1, nval, min_nvalm, min_nvalp, maxc;
- real omega_m1_0, omega_p1_0, clam_osum;
- real de, de_function;
- real cnval, zero_sum_weights;
+ int min_nvalm, min_nvalp, maxc;
+ real omega_m1_0, omega_p1_0;
+ real zero_sum_weights;
real *omegam_array, *weightsm_array, *omegap_array, *weightsp_array, *varm_array, *varp_array,
*dwp_array, *dwm_array;
- real clam_varm, clam_varp, clam_weightsm, clam_weightsp, clam_minvar;
+ real clam_varm, clam_varp, clam_osum, clam_weightsm, clam_weightsp, clam_minvar;
real * lam_variance, *lam_dg;
double* p_k;
double pks = 0;
- real chi_m1_0, chi_p1_0, chi_m2_0, chi_p2_0, chi_p1_m1, chi_p2_m1, chi_m1_p1, chi_m2_p1;
- /* if we have equilibrated the weights, exit now */
+ /* Future potential todos for this function (see #3848):
+ * - Update the names in the dhist structure to be clearer. Not done for now since this
+ * a bugfix update and we are mininizing other code changes.
+ * - Modularize the code some more.
+ * - potentially merge with accelerated weight histogram functionality, since it's very similar.
+ */
+ /* if we have equilibrated the expanded ensemble weights, we are not updating them, so exit now */
if (dfhist->bEquil)
{
return FALSE;
if (EWL(expand->elamstats))
{
- if (expand->elamstats == elamstatsWL) /* Standard Wang-Landau */
+ if (expand->elamstats == elamstatsWL) /* 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) /* Weighted Wang-Landau */
+ else if (expand->elamstats == elamstatsWWL)
+ /* Using weighted Wang-Landau for weight updates.
+ * Very closly equivalent to accelerated weight histogram approach
+ * applied to expanded ensemble. */
{
snew(p_k, 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++)
{
if (expand->elamstats == elamstatsBARKER || expand->elamstats == elamstatsMETROPOLIS
|| expand->elamstats == elamstatsMINVAR)
{
-
- de_function = 0; /* to get rid of warnings, but this value will not be used because of the logic */
maxc = 2 * expand->c_range + 1;
snew(lam_dg, nlim);
snew(varm_array, maxc);
snew(dwm_array, maxc);
- /* unpack the current lambdas -- we will only update 2 of these */
+ /* unpack the values of the free energy differences and the
+ * variance in their estimates between nearby lambdas. We will
+ * only actually update 2 of these, the state we are currently
+ * at and the one we end up moving to
+ */
for (i = 0; i < nlim - 1; i++)
{ /* only through the second to last */
gmx::square(dfhist->sum_variance[i + 1]) - gmx::square(dfhist->sum_variance[i]);
}
- /* accumulate running averages */
- for (nval = 0; nval < maxc; nval++)
+ /* accumulate running averages of thermodynamic averages for Bennett Acceptance Ratio-based
+ * estimates of the free energy .
+ * Rather than peforming self-consistent estimation of the free energies at each step,
+ * we keep track of an array of possible different free energies (cnvals),
+ * and we self-consistently choose the best one. The one that leads to a free energy estimate
+ * that is closest to itself is the best estimate of the free energy. It is essentially a
+ * parallellized version of self-consistent iteration. maxc is the number of these constants. */
+
+ for (int nval = 0; nval < maxc; nval++)
{
- /* constants for later use */
- cnval = static_cast<real>(nval - expand->c_range);
- /* actually, should be able to rewrite it w/o exponential, for better numerical stability */
+ const real cnval = static_cast<real>(nval - expand->c_range);
+
+ /* Compute acceptance criterion weight to the state below this one for use in averages.
+ * Note we do not have to have just moved from that state to use this free energy
+ * estimate; these are essentially "virtual" moves. */
+
if (fep_state > 0)
{
- de = std::exp(cnval - (scaled_lamee[fep_state] - scaled_lamee[fep_state - 1]));
- if (expand->elamstats == elamstatsBARKER || expand->elamstats == elamstatsMINVAR)
- {
- de_function = 1.0 / (1.0 + de);
- }
- else if (expand->elamstats == elamstatsMETROPOLIS)
- {
- if (de < 1.0)
- {
- de_function = 1.0;
- }
- else
- {
- de_function = 1.0 / de;
- }
- }
- dfhist->accum_m[fep_state][nval] += de_function;
- dfhist->accum_m2[fep_state][nval] += de_function * de_function;
+ const auto lambdaEnergyDifference =
+ cnval - (scaled_lamee[fep_state] - scaled_lamee[fep_state - 1]);
+ acceptanceWeight =
+ gmx::calculateAcceptanceWeight(expand->elamstats, lambdaEnergyDifference);
+ dfhist->accum_m[fep_state][nval] += acceptanceWeight;
+ dfhist->accum_m2[fep_state][nval] += acceptanceWeight * acceptanceWeight;
}
+ // Compute acceptance criterion weight to transition to the next state
if (fep_state < nlim - 1)
{
- de = std::exp(-cnval + (scaled_lamee[fep_state + 1] - scaled_lamee[fep_state]));
- if (expand->elamstats == elamstatsBARKER || expand->elamstats == elamstatsMINVAR)
- {
- de_function = 1.0 / (1.0 + de);
- }
- else if (expand->elamstats == elamstatsMETROPOLIS)
- {
- if (de < 1.0)
- {
- de_function = 1.0;
- }
- else
- {
- de_function = 1.0 / de;
- }
- }
- dfhist->accum_p[fep_state][nval] += de_function;
- dfhist->accum_p2[fep_state][nval] += de_function * de_function;
+ const auto lambdaEnergyDifference =
+ -cnval + (scaled_lamee[fep_state + 1] - scaled_lamee[fep_state]);
+ acceptanceWeight =
+ gmx::calculateAcceptanceWeight(expand->elamstats, lambdaEnergyDifference);
+ dfhist->accum_p[fep_state][nval] += acceptanceWeight;
+ dfhist->accum_p2[fep_state][nval] += acceptanceWeight * acceptanceWeight;
}
- /* Metropolis transition and Barker transition (unoptimized Bennett) acceptance weight determination */
+ /* Determination of Metropolis transition and Barker transition weights */
- n0 = dfhist->n_at_lam[fep_state];
+ int numObservationsCurrentState = dfhist->n_at_lam[fep_state];
+ /* determine the number of observations above and below the current state */
+ int numObservationsLowerState = 0;
if (fep_state > 0)
{
- nm1 = dfhist->n_at_lam[fep_state - 1];
- }
- else
- {
- nm1 = 0;
+ numObservationsLowerState = dfhist->n_at_lam[fep_state - 1];
}
+ int numObservationsHigherState = 0;
if (fep_state < nlim - 1)
{
- np1 = dfhist->n_at_lam[fep_state + 1];
- }
- else
- {
- np1 = 0;
+ numObservationsHigherState = dfhist->n_at_lam[fep_state + 1];
}
- /* logic SHOULD keep these all set correctly whatever the logic, but apparently it can't figure it out. */
- chi_m1_0 = chi_p1_0 = chi_m2_0 = chi_p2_0 = chi_p1_m1 = chi_p2_m1 = chi_m1_p1 = chi_m2_p1 = 0;
+ /* Calculate the biases for each expanded ensemble state that minimize the total
+ * variance, as implemented in Martinez-Veracoechea and Escobedo,
+ * J. Phys. Chem. B 2008, 112, 8120-8128
+ *
+ * The variance associated with the free energy estimate between two states i and j
+ * is calculated as
+ * Var(i,j) = {avg[xi(i->j)^2] / avg[xi(i->j)]^2 - 1} / numObservations(i->j)
+ * + {avg[xi(j->i)^2] / avg[xi(j->i)]^2 - 1} / numObservations(j->i)
+ * where xi(i->j) is the acceptance factor / weight associated with moving from state i to j
+ * As we are calculating the acceptance factor to the neighbors every time we're visiting
+ * a state, numObservations(i->j) == numObservations(i) and numObservations(j->i) == numObservations(j)
+ */
- if (n0 > 0)
+ /* Accumulation of acceptance weight averages between the current state and the
+ * states +1 (p1) and -1 (m1), averaged at current state (0)
+ */
+ real avgAcceptanceCurrentToLower = 0;
+ real avgAcceptanceCurrentToHigher = 0;
+ /* Accumulation of acceptance weight averages quantities between states 0
+ * and states +1 and -1, squared
+ */
+ real avgAcceptanceCurrentToLowerSquared = 0;
+ real avgAcceptanceCurrentToHigherSquared = 0;
+ /* Accumulation of free energy quantities from lower state (m1) to current state (0) and squared */
+ real avgAcceptanceLowerToCurrent = 0;
+ real avgAcceptanceLowerToCurrentSquared = 0;
+ /* Accumulation of free energy quantities from upper state (p1) to current state (0) and squared */
+ real avgAcceptanceHigherToCurrent = 0;
+ real avgAcceptanceHigherToCurrentSquared = 0;
+
+ if (numObservationsCurrentState > 0)
{
- chi_m1_0 = dfhist->accum_m[fep_state][nval] / n0;
- chi_p1_0 = dfhist->accum_p[fep_state][nval] / n0;
- chi_m2_0 = dfhist->accum_m2[fep_state][nval] / n0;
- chi_p2_0 = dfhist->accum_p2[fep_state][nval] / n0;
+ avgAcceptanceCurrentToLower = dfhist->accum_m[fep_state][nval] / numObservationsCurrentState;
+ avgAcceptanceCurrentToHigher =
+ dfhist->accum_p[fep_state][nval] / numObservationsCurrentState;
+ avgAcceptanceCurrentToLowerSquared =
+ dfhist->accum_m2[fep_state][nval] / numObservationsCurrentState;
+ avgAcceptanceCurrentToHigherSquared =
+ dfhist->accum_p2[fep_state][nval] / numObservationsCurrentState;
}
- if ((fep_state > 0) && (nm1 > 0))
+ if ((fep_state > 0) && (numObservationsLowerState > 0))
{
- chi_p1_m1 = dfhist->accum_p[fep_state - 1][nval] / nm1;
- chi_p2_m1 = dfhist->accum_p2[fep_state - 1][nval] / nm1;
+ avgAcceptanceLowerToCurrent =
+ dfhist->accum_p[fep_state - 1][nval] / numObservationsLowerState;
+ avgAcceptanceLowerToCurrentSquared =
+ dfhist->accum_p2[fep_state - 1][nval] / numObservationsLowerState;
}
- if ((fep_state < nlim - 1) && (np1 > 0))
+ if ((fep_state < nlim - 1) && (numObservationsHigherState > 0))
{
- chi_m1_p1 = dfhist->accum_m[fep_state + 1][nval] / np1;
- chi_m2_p1 = dfhist->accum_m2[fep_state + 1][nval] / np1;
+ avgAcceptanceHigherToCurrent =
+ dfhist->accum_m[fep_state + 1][nval] / numObservationsHigherState;
+ avgAcceptanceHigherToCurrentSquared =
+ dfhist->accum_m2[fep_state + 1][nval] / numObservationsHigherState;
}
-
- omega_m1_0 = 0;
- omega_p1_0 = 0;
- clam_weightsm = 0;
- clam_weightsp = 0;
- clam_varm = 0;
- clam_varp = 0;
+ /* These are accumulation of positive values (see definition of acceptance functions
+ * above), or of squares of positive values.
+ * We're taking this for granted in the following calculation, so make sure
+ * here that nothing weird happened. Although technically all values should be positive,
+ * because of floating point precisions, they might be numerically zero. */
+ GMX_RELEASE_ASSERT(
+ avgAcceptanceCurrentToLower >= 0 && avgAcceptanceCurrentToLowerSquared >= 0
+ && avgAcceptanceCurrentToHigher >= 0
+ && avgAcceptanceCurrentToHigherSquared >= 0 && avgAcceptanceLowerToCurrent >= 0
+ && avgAcceptanceLowerToCurrentSquared >= 0 && avgAcceptanceHigherToCurrent >= 0
+ && avgAcceptanceHigherToCurrentSquared >= 0,
+ "By definition, the acceptance factors should all be nonnegative.");
+
+ real varianceCurrentToLower = 0;
+ real varianceCurrentToHigher = 0;
+ real weightDifferenceToLower = 0;
+ real weightDifferenceToHigher = 0;
+ real varianceToLower = 0;
+ real varianceToHigher = 0;
if (fep_state > 0)
{
- if (n0 > 0)
+ if (numObservationsCurrentState > 0)
{
- omega_m1_0 = chi_m2_0 / (chi_m1_0 * chi_m1_0) - 1.0;
- if (nm1 > 0)
+ /* Calculate {avg[xi(i->j)^2] / avg[xi(i->j)]^2 - 1}
+ *
+ * Note that if avg[xi(i->j)] == 0, also avg[xi(i->j)^2] == 0 (since the
+ * acceptances are all positive!), and hence
+ * {avg[xi(i->j)^2] / avg[xi(i->j)]^2 - 1} -> 0 for avg[xi(i->j)] -> 0
+ * We're catching that case explicitly to avoid numerical
+ * problems dividing by zero when the overlap between states is small (#3304)
+ */
+ if (avgAcceptanceCurrentToLower > 0)
{
- real omega_p1_m1 = chi_p2_m1 / (chi_p1_m1 * chi_p1_m1) - 1.0;
- clam_weightsm = (std::log(chi_m1_0) - std::log(chi_p1_m1)) + cnval;
- clam_varm = (1.0 / n0) * (omega_m1_0) + (1.0 / nm1) * (omega_p1_m1);
+ varianceCurrentToLower =
+ avgAcceptanceCurrentToLowerSquared
+ / (avgAcceptanceCurrentToLower * avgAcceptanceCurrentToLower)
+ - 1.0;
+ }
+ if (numObservationsLowerState > 0)
+ {
+ /* Calculate {avg[xi(i->j)^2] / avg[xi(i->j)]^2 - 1}
+ *
+ * Note that if avg[xi(i->j)] == 0, also avg[xi(i->j)^2] == 0 (since the
+ * acceptances are all positive!), and hence
+ * {avg[xi(i->j)^2] / avg[xi(i->j)]^2 - 1} -> 0 for avg[xi(i->j)] -> 0
+ * We're catching that case explicitly to avoid numerical
+ * problems dividing by zero when the overlap between states is small (#3304)
+ */
+ real varianceLowerToCurrent = 0;
+ if (avgAcceptanceLowerToCurrent > 0)
+ {
+ varianceLowerToCurrent =
+ avgAcceptanceLowerToCurrentSquared
+ / (avgAcceptanceLowerToCurrent * avgAcceptanceLowerToCurrent)
+ - 1.0;
+ }
+ /* Free energy difference to the state one state lower */
+ /* if these either of these quantities are zero, the energies are */
+ /* way too large for the dynamic range. We need an alternate guesstimate */
+ if ((avgAcceptanceCurrentToLower == 0) || (avgAcceptanceLowerToCurrent == 0))
+ {
+ weightDifferenceToLower =
+ (scaled_lamee[fep_state] - scaled_lamee[fep_state - 1]);
+ }
+ else
+ {
+ weightDifferenceToLower = (std::log(avgAcceptanceCurrentToLower)
+ - std::log(avgAcceptanceLowerToCurrent))
+ + cnval;
+ }
+ /* Variance of the free energy difference to the one state lower */
+ varianceToLower =
+ (1.0 / numObservationsCurrentState) * (varianceCurrentToLower)
+ + (1.0 / numObservationsLowerState) * (varianceLowerToCurrent);
}
}
}
if (fep_state < nlim - 1)
{
- if (n0 > 0)
+ if (numObservationsCurrentState > 0)
{
- omega_p1_0 = chi_p2_0 / (chi_p1_0 * chi_p1_0) - 1.0;
- if (np1 > 0)
+ /* Calculate {avg[xi(i->j)^2] / avg[xi(i->j)]^2 - 1}
+ *
+ * Note that if avg[xi(i->j)] == 0, also avg[xi(i->j)^2] == 0 (since the
+ * acceptances are all positive!), and hence
+ * {avg[xi(i->j)^2] / avg[xi(i->j)]^2 - 1} -> 0 for avg[xi(i->j)] -> 0
+ * We're catching that case explicitly to avoid numerical
+ * problems dividing by zero when the overlap between states is small (#3304)
+ */
+
+ if (avgAcceptanceCurrentToHigher < 0)
+ {
+ varianceCurrentToHigher =
+ avgAcceptanceCurrentToHigherSquared
+ / (avgAcceptanceCurrentToHigher * avgAcceptanceCurrentToHigher)
+ - 1.0;
+ }
+ if (numObservationsHigherState > 0)
{
- real omega_m1_p1 = chi_m2_p1 / (chi_m1_p1 * chi_m1_p1) - 1.0;
- clam_weightsp = (std::log(chi_m1_p1) - std::log(chi_p1_0)) + cnval;
- clam_varp = (1.0 / np1) * (omega_m1_p1) + (1.0 / n0) * (omega_p1_0);
+ /* Calculate {avg[xi(i->j)^2] / avg[xi(i->j)]^2 - 1}
+ *
+ * Note that if avg[xi(i->j)] == 0, also avg[xi(i->j)^2] == 0 (since the
+ * acceptances are all positive!), and hence
+ * {avg[xi(i->j)^2] / avg[xi(i->j)]^2 - 1} -> 0 for avg[xi(i->j)] -> 0
+ * We're catching that case explicitly to avoid numerical
+ * problems dividing by zero when the overlap between states is small (#3304)
+ */
+ real varianceHigherToCurrent = 0;
+ if (avgAcceptanceHigherToCurrent > 0)
+ {
+ varianceHigherToCurrent =
+ avgAcceptanceHigherToCurrentSquared
+ / (avgAcceptanceHigherToCurrent * avgAcceptanceHigherToCurrent)
+ - 1.0;
+ }
+ /* Free energy difference to the state one state higher */
+ /* if these either of these quantities are zero, the energies are */
+ /* way too large for the dynamic range. We need an alternate guesstimate */
+ if ((avgAcceptanceHigherToCurrent == 0) || (avgAcceptanceCurrentToHigher == 0))
+ {
+ weightDifferenceToHigher =
+ (scaled_lamee[fep_state + 1] - scaled_lamee[fep_state]);
+ }
+ else
+ {
+ weightDifferenceToHigher = (std::log(avgAcceptanceHigherToCurrent)
+ - std::log(avgAcceptanceCurrentToHigher))
+ + cnval;
+ }
+ /* Variance of the free energy difference to the one state higher */
+ varianceToHigher =
+ (1.0 / numObservationsHigherState) * (varianceHigherToCurrent)
+ + (1.0 / numObservationsCurrentState) * (varianceCurrentToHigher);
}
}
}
- if (n0 > 0)
+ if (numObservationsCurrentState > 0)
{
- omegam_array[nval] = omega_m1_0;
+ omegam_array[nval] = varianceCurrentToLower;
}
else
{
omegam_array[nval] = 0;
}
- weightsm_array[nval] = clam_weightsm;
- varm_array[nval] = clam_varm;
- if (nm1 > 0)
+ weightsm_array[nval] = weightDifferenceToLower;
+ varm_array[nval] = varianceToLower;
+ if (numObservationsLowerState > 0)
{
- dwm_array[nval] = fabs((cnval + std::log((1.0 * n0) / nm1)) - lam_dg[fep_state - 1]);
+ dwm_array[nval] =
+ fabs((cnval + std::log((1.0 * numObservationsCurrentState) / numObservationsLowerState))
+ - lam_dg[fep_state - 1]);
}
else
{
dwm_array[nval] = std::fabs(cnval - lam_dg[fep_state - 1]);
}
- if (n0 > 0)
+ if (numObservationsCurrentState > 0)
{
- omegap_array[nval] = omega_p1_0;
+ omegap_array[nval] = varianceCurrentToHigher;
}
else
{
omegap_array[nval] = 0;
}
- weightsp_array[nval] = clam_weightsp;
- varp_array[nval] = clam_varp;
- if ((np1 > 0) && (n0 > 0))
+ weightsp_array[nval] = weightDifferenceToHigher;
+ varp_array[nval] = varianceToHigher;
+ if ((numObservationsHigherState > 0) && (numObservationsCurrentState > 0))
{
- dwp_array[nval] = fabs((cnval + std::log((1.0 * np1) / n0)) - lam_dg[fep_state]);
+ dwp_array[nval] =
+ fabs((cnval + std::log((1.0 * numObservationsHigherState) / numObservationsCurrentState))
+ - lam_dg[fep_state]);
}
else
{
}
}
- /* find the C's closest to the old weights value */
+ /* find the free energy estimate closest to the guessed weight's value */
min_nvalm = FindMinimum(dwm_array, maxc);
omega_m1_0 = omegam_array[min_nvalm];
if (expand->elamstats == elamstatsMINVAR)
{
bSufficientSamples = TRUE;
- /* make sure they are all past a threshold */
+ /* make sure the number of samples in each state are all
+ * past a user-specified threshold
+ */
for (i = 0; i < nlim; i++)
{
if (dfhist->n_at_lam[i] < expand->minvarmin)
"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);
}
de = weighted_lamee[lamtrial] - weighted_lamee[fep_state];
if (expand->elmcmove == elmcmoveMETROPOLIS)
{
- tprob = 1.0;
- trialprob = std::exp(de);
- if (trialprob < tprob)
+ tprob = 1.0;
+ if (de < 0)
{
- tprob = trialprob;
+ tprob = std::exp(de);
}
propose[fep_state] = 0;
propose[lamtrial] = 1.0; /* note that this overwrites the above line if fep_state = ntrial, which only occurs at the ends */
}
else if (expand->elmcmove == elmcmoveBARKER)
{
- tprob = 1.0 / (1.0 + std::exp(-de));
-
+ if (de > 0) /* Numerically stable version */
+ {
+ tprob = 1.0 / (1.0 + std::exp(-de));
+ }
+ else if (de < 0)
+ {
+ tprob = std::exp(de) / (std::exp(de) + 1.0);
+ }
propose[fep_state] = (1 - tprob);
propose[lamtrial] +=
tprob; /* we add, to account for the fact that at the end, they might be the same point */
}
if (expand->elamstats == elamstatsMINVAR)
{
- 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
{
}
int ExpandedEnsembleDynamics(FILE* log,
- const t_inputrec* ir,
+ t_inputrec* ir,
const gmx_enerdata_t* enerd,
t_state* state,
t_extmass* MassQ,
{
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,
+ elmceq_names[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 */
{
/*
* 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.
{
StringOutputStream stream;
TextWriter writer(&stream);
- writer.writeStringFormatted(
+ writer.writeLineFormatted(
"Some output files listed in the checkpoint file %s are not present or not named "
"as the output files by the current program:)",
checkpointFilename);
- auto settings = writer.wrapperSettings();
- auto oldIndent = settings.indent(), newIndent = 2;
+ auto& settings = writer.wrapperSettings();
+ auto oldIndent = settings.indent(), newIndent = 2;
writer.writeLine("Expected output files that are present:");
settings.setIndent(newIndent);
+ settings.setLineLength(78);
for (const auto& outputfile : outputfiles)
{
if (exist_output_file(outputfile.filename, nfile, fnm))
settings.setIndent(oldIndent);
writer.ensureEmptyLine();
+ // The implementation of -deffnm does not handle properly the
+ // naming of output files that share a common suffix, such as
+ // pullx.xvg and pullf.xvg from the pull module. Such output files
+ // will be sought by the wrong name by the code that handles the
+ // restart, even though the pull module would later work out what
+ // they should have been called. Since there is a straightforward
+ // way to work around that, we help the user with that. This can
+ // be removed when gitlab issue #3875 is resolved.
+ bool missingFilesIncludedPullOutputFiles = false;
writer.writeLine("Expected output files that are not present or named differently:");
settings.setIndent(newIndent);
for (const auto& outputfile : outputfiles)
if (!exist_output_file(outputfile.filename, nfile, fnm))
{
writer.writeLine(outputfile.filename);
+ // If this was a pull file, then we have a known issue and
+ // work-around (See gitlab issue #3442).
+ if (!missingFilesIncludedPullOutputFiles
+ && (contains(outputfile.filename, "pullx")
+ || contains(outputfile.filename, "pullf")))
+ {
+ missingFilesIncludedPullOutputFiles = true;
+ }
}
}
+ if (missingFilesIncludedPullOutputFiles)
+ {
+ writer.ensureEmptyLine();
+ writer.writeLineFormatted(
+ "It appears that pull output files were not found. It is known that "
+ "using gmx mdrun -deffnm test with pulling and later "
+ "gmx mdrun -deffnm test -cpi will fail to consider the changed default "
+ "filename when checking the pull output files for restarting with "
+ "appending. You may be able to work around this by using a command like "
+ "gmx mdrun -deffnm test -px test_pullx -pf test_pullf -cpi.");
+ }
settings.setIndent(oldIndent);
+ writer.ensureEmptyLine();
writer.writeLineFormatted(
- R"(To keep your simulation files safe, this simulation will not restart. Either name your
- output files exactly the same as the previous simulation part (e.g. with -deffnm), or
- make sure all the output files are present (e.g. run from the same directory as the
- previous simulation 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.)",
+ "To keep your simulation files safe, this simulation will not restart. "
+ "Either name your output files exactly the same as the previous simulation "
+ "part (e.g. with -deffnm or explicit naming), or make sure all the output "
+ "files are present (e.g. run from the same directory as the previous simulation "
+ "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()));
}
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)
"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
"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));
}
}
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 = {
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));
}
// 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)
{
/*
* 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.
{
class StopHandler;
class TrajectoryElement;
+ enum class StartingBehavior;
/*! \internal
* \ingroup module_modularsimulator
private:
/*! \brief Constructor
*
- * \param callbacks A vector of pointers to callbacks
- * \param nstlog The logging frequency
- * \param initStep The first step of the simulation
- * \param initTime The start time of the simulation
+ * \param callbacks A vector of pointers to callbacks
+ * \param nstlog The logging frequency
+ * \param initStep The first step of the simulation
+ * \param startingBehavior Whether this is a new simulation or restarting from checkpoint
*/
- LoggingSignaller(std::vector<SignallerCallback> callbacks, Step nstlog, Step initStep, Time initTime);
+ LoggingSignaller(std::vector<SignallerCallback> callbacks,
+ Step nstlog,
+ Step initStep,
+ StartingBehavior startingBehavior);
//! Client callbacks
std::vector<SignallerCallback> callbacks_;
const Step nstlog_;
//! The initial step of the simulation
const Step initStep_;
- //! The initial time of the simulation
- const Time initTime_;
+ //! How we are starting the simulation
+ const StartingBehavior startingBehavior_;
//! ILastStepSignallerClient implementation
std::optional<SignallerCallback> registerLastStepCallback() override;
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
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,
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
{
}
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");
}
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()
}
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->mdModulesNotifier,
+ MASTER(legacySimulatorData->cr),
+ legacySimulatorData->observablesHistory,
+ legacySimulatorData->startingBehavior,
+ simulationsShareState);
}
ModularSimulatorAlgorithm ModularSimulatorAlgorithmBuilder::build()
}
}
- 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_);
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
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
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_->mdModulesNotifier,
+ legacySimulatorData_->inputrec,
+ legacySimulatorData_->top_global,
+ legacySimulatorData_->oenv,
+ legacySimulatorData_->wcycle,
+ legacySimulatorData_->startingBehavior,
+ simulationsShareState);
registerWithInfrastructureAndSignallers(trajectoryElement.get());
// Build free energy element
{
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());
}
const auto* inputrec = legacySimulatorData_->inputrec;
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));
+ 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, inputrec->init_t));
++ 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
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;
}
* 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.
const nbnxn_atomdata_t::Params& nbatParams,
const DeviceContext& deviceContext)
{
- int ntypes;
-
- ntypes = nbatParams.numTypes;
+ const int ntypes = nbatParams.numTypes;
set_cutoff_parameters(nbp, ic, listParams);
* 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!");
- }
+ nbp->vdwType = nbnxmGpuPickVdwKernelType(ic, nbatParams.comb_rule);
- nbp->elecType = nbnxmGpuPickElectrostaticsKernelType(ic);
++ nbp->elecType = nbnxmGpuPickElectrostaticsKernelType(ic, deviceContext.deviceInfo());
/* generate table for PME */
nbp->coulomb_tab = nullptr;
- if (nbp->eeltype == eelTypeEWALD_TAB || nbp->eeltype == eelTypeEWALD_TAB_TWIN)
+ 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))
+ if (!useLjCombRule(nbp->vdwType))
{
- initParamLookupTable(&nbp->nbfp, &nbp->nbfp_texobj, nbatParams.nbfp.data(),
- 2 * ntypes * ntypes, deviceContext);
+ 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);
+ initParamLookupTable(
+ &nbp->nbfp_comb, &nbp->nbfp_comb_texobj, nbatParams.nbfp_comb.data(), 2 * ntypes, deviceContext);
}
}
{
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);
+ copyToDeviceBuffer(&adat->shift_vec,
+ reinterpret_cast<const float3*>(nbatom->shift_vec.data()),
+ 0,
+ SHIFTS,
+ localStream,
+ GpuApiCallBehavior::Async,
+ nullptr);
adat->bShiftVecUploaded = true;
}
}
allocateDeviceBuffer(&d_atdat->f, nalloc, deviceContext);
allocateDeviceBuffer(&d_atdat->xq, nalloc, deviceContext);
- if (useLjCombRule(nb->nbparam->vdwtype))
+ if (useLjCombRule(nb->nbparam->vdwType))
{
allocateDeviceBuffer(&d_atdat->lj_comb, nalloc, deviceContext);
}
nbnxn_cuda_clear_f(nb, nalloc);
}
- if (useLjCombRule(nb->nbparam->vdwtype))
+ 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);
+ 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);
+ copyToDeviceBuffer(&d_atdat->atom_types,
+ nbat->params().type.data(),
+ 0,
+ natoms,
+ localStream,
+ GpuApiCallBehavior::Async,
+ nullptr);
}
if (bDoTime)
nbparam = nb->nbparam;
if ((!nbparam->coulomb_tab)
- && (nbparam->eeltype == eelTypeEWALD_TAB || nbparam->eeltype == eelTypeEWALD_TAB_TWIN))
+ && (nbparam->elecType == ElecType::EwaldTab || nbparam->elecType == ElecType::EwaldTabTwin))
{
destroyParamLookupTable(&nbparam->coulomb_tab, nbparam->coulomb_tab_texobj);
}
delete nb->timers;
- if (!useLjCombRule(nb->nbparam->vdwtype))
+ if (!useLjCombRule(nb->nbparam->vdwType))
{
destroyParamLookupTable(&nbparam->nbfp, nbparam->nbfp_texobj);
}
- if (nbparam->vdwtype == evdwTypeEWALDGEOM || nbparam->vdwtype == evdwTypeEWALDLB)
+ if (nbparam->vdwType == VdwType::EwaldGeom || nbparam->vdwType == VdwType::EwaldLB)
{
destroyParamLookupTable(&nbparam->nbfp_comb, nbparam->nbfp_comb_texobj);
}
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_);
+ 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 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_);
+ reallocateDeviceBuffer(&gpu_nbv->atomIndices,
+ atomIndicesSize,
+ &gpu_nbv->atomIndicesSize,
+ &gpu_nbv->atomIndicesSize_alloc,
+ *gpu_nbv->deviceContext_);
if (atomIndicesSize > 0)
{
gpu_nbv->timers->xf[AtomLocality::Local].nb_h2d.openTimingRegion(deviceStream);
}
- copyToDeviceBuffer(&gpu_nbv->atomIndices, atomIndices, 0, atomIndicesSize, deviceStream,
- GpuApiCallBehavior::Async, nullptr);
+ copyToDeviceBuffer(&gpu_nbv->atomIndices,
+ atomIndices,
+ 0,
+ atomIndicesSize,
+ deviceStream,
+ GpuApiCallBehavior::Async,
+ nullptr);
if (bDoTime)
{
}
int* destPtr = &gpu_nbv->cxy_na[maxNumColumns * g];
- copyToDeviceBuffer(&destPtr, cxy_na, 0, numColumns, deviceStream,
- GpuApiCallBehavior::Async, nullptr);
+ copyToDeviceBuffer(
+ &destPtr, cxy_na, 0, numColumns, deviceStream, GpuApiCallBehavior::Async, nullptr);
if (bDoTime)
{
}
destPtr = &gpu_nbv->cxy_ind[maxNumColumns * g];
- copyToDeviceBuffer(&destPtr, cxy_ind, 0, numColumns, deviceStream,
- GpuApiCallBehavior::Async, nullptr);
+ copyToDeviceBuffer(
+ &destPtr, cxy_ind, 0, numColumns, deviceStream, GpuApiCallBehavior::Async, nullptr);
if (bDoTime)
{
* 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.
#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;
GPU_FUNC_QUALIFIER
bool gpu_is_kernel_ewald_analytical(const NbnxmGpu gmx_unused* nb) GPU_FUNC_TERM_WITH_RETURN(FALSE);
- enum ElecType nbnxmGpuPickElectrostaticsKernelType(const interaction_const_t gmx_unused* ic)
+/** Return the enum value of electrostatics kernel type for given interaction parameters \p ic. */
+GPU_FUNC_QUALIFIER
++enum ElecType nbnxmGpuPickElectrostaticsKernelType(const interaction_const_t gmx_unused* ic,
++ const DeviceInformation gmx_unused& deviceInfo)
+ GPU_FUNC_TERM_WITH_RETURN(ElecType::Count);
+
+/** Return the enum value of VdW kernel type for given \p ic and \p combRule. */
+GPU_FUNC_QUALIFIER
+enum VdwType nbnxmGpuPickVdwKernelType(const interaction_const_t gmx_unused* ic, int gmx_unused combRule)
+ GPU_FUNC_TERM_WITH_RETURN(VdwType::Count);
+
/** Returns an opaque pointer to the GPU command stream
* Note: CUDA only.
*/
* 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 "nbnxm_gpu_data_mgmt.h"
+ #include "gromacs/hardware/device_information.h"
+#include "gromacs/mdtypes/interaction_const.h"
#include "gromacs/nbnxm/gpu_data_mgmt.h"
#include "gromacs/timing/gpu_timing.h"
#include "gromacs/utility/cstringutil.h"
}
nbp->coulomb_tab_scale = tables.scale;
- initParamLookupTable(&nbp->coulomb_tab, &nbp->coulomb_tab_texobj, tables.tableF.data(),
- tables.tableF.size(), deviceContext);
+ initParamLookupTable(
+ &nbp->coulomb_tab, &nbp->coulomb_tab_texobj, tables.tableF.data(), tables.tableF.size(), deviceContext);
}
void inline printEnvironmentVariableDeprecationMessage(bool isEnvironmentVariableSet,
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(),
+ environmentVariableSuffix.c_str(),
environmentVariableSuffix.c_str());
}
}
- enum ElecType nbnxn_gpu_pick_ewald_kernel_type(const interaction_const_t& ic)
-int nbnxn_gpu_pick_ewald_kernel_type(const interaction_const_t& ic,
- const DeviceInformation gmx_unused& deviceInfo)
++enum 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. */
"requested through environment variables.");
}
- /* By default, use analytical Ewald
- * TODO: tabulated does not work in OpenCL, it needs fixing, see init_nbparam() in nbnxn_ocl_data_mgmt.cpp
- *
+ /* By default, use analytical Ewald except with CUDA on NVIDIA CC 7.0 and 8.0.
*/
- bool bUseAnalyticalEwald = true;
+ const bool c_useTabulatedEwaldDefault =
+ #if GMX_GPU_CUDA
+ (deviceInfo.prop.major == 7 && deviceInfo.prop.minor == 0)
+ || (deviceInfo.prop.major == 8 && deviceInfo.prop.minor == 0);
+ #else
+ false;
+ #endif
+ bool bUseAnalyticalEwald = !c_useTabulatedEwaldDefault;
if (forceAnalyticalEwald)
{
+ bUseAnalyticalEwald = true;
if (debug)
{
fprintf(debug, "Using analytical Ewald GPU kernels\n");
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)
set_cutoff_parameters(nbp, ic, nbv->pairlistSets().params());
- nbp->elecType = nbnxn_gpu_pick_ewald_kernel_type(*ic);
- nbp->eeltype = nbnxn_gpu_pick_ewald_kernel_type(*ic, nb->deviceContext_->deviceInfo());
++ 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_);
{
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);
}
}
// 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->cj4, h_plist->cj4.size(), &d_plist->ncj4, &d_plist->cj4_nalloc,
+ 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->imask,
+ h_plist->cj4.size() * c_nbnxnGpuClusterpairSplit,
+ &d_plist->nimask,
+ &d_plist->imask_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->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)
{
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));
+}
+
- enum ElecType nbnxmGpuPickElectrostaticsKernelType(const interaction_const_t* ic)
++enum ElecType nbnxmGpuPickElectrostaticsKernelType(const interaction_const_t* ic,
++ const DeviceInformation& deviceInfo)
+{
+ if (ic->eeltype == eelCUT)
+ {
+ return ElecType::Cut;
+ }
+ else if (EEL_RF(ic->eeltype))
+ {
+ return ElecType::RF;
+ }
+ else if ((EEL_PME(ic->eeltype) || ic->eeltype == eelEWALD))
+ {
- return nbnxn_gpu_pick_ewald_kernel_type(*ic);
++ 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 (%d) is not implemented in "
+ "the GPU accelerated kernels!",
+ EELTYPE(ic->eeltype),
+ ic->eeltype)));
+ }
+}
+
+
+enum VdwType nbnxmGpuPickVdwKernelType(const interaction_const_t* ic, int combRule)
+{
+ if (ic->vdwtype == evdwCUT)
+ {
+ switch (ic->vdw_modifier)
+ {
+ case eintmodNONE:
+ case eintmodPOTSHIFT:
+ switch (combRule)
+ {
+ case ljcrNONE: return VdwType::Cut;
+ case ljcrGEOM: return VdwType::CutCombGeom;
+ case ljcrLB: return VdwType::CutCombLB;
+ default:
+ GMX_THROW(gmx::InconsistentInputError(gmx::formatString(
+ "The requested LJ combination rule %s (%d) is not implemented in "
+ "the GPU accelerated kernels!",
+ enum_name(combRule, ljcrNR, c_ljcrNames),
+ combRule)));
+ }
+ case eintmodFORCESWITCH: return VdwType::FSwitch;
+ case eintmodPOTSWITCH: return VdwType::PSwitch;
+ default:
+ GMX_THROW(gmx::InconsistentInputError(
+ gmx::formatString("The requested VdW interaction modifier %s (%d) is not "
+ "implemented in the GPU accelerated kernels!",
+ INTMODIFIER(ic->vdw_modifier),
+ ic->vdw_modifier)));
+ }
+ }
+ else if (ic->vdwtype == evdwPME)
+ {
+ if (ic->ljpme_comb_rule == ljcrGEOM)
+ {
+ assert(combRule == ljcrGEOM);
+ return VdwType::EwaldGeom;
+ }
+ else
+ {
+ assert(combRule == ljcrLB);
+ return VdwType::EwaldLB;
+ }
+ }
+ else
+ {
+ GMX_THROW(gmx::InconsistentInputError(gmx::formatString(
+ "The requested VdW type %s (%d) is not implemented in the GPU accelerated kernels!",
+ EVDWTYPE(ic->vdwtype),
+ ic->vdwtype)));
+ }
}
} // namespace Nbnxm
* 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.
const DeviceContext& deviceContext);
/*! \brief Selects the Ewald kernel type, analytical or tabulated, single or twin cut-off. */
- enum ElecType nbnxn_gpu_pick_ewald_kernel_type(const interaction_const_t gmx_unused& ic);
-int nbnxn_gpu_pick_ewald_kernel_type(const interaction_const_t gmx_unused& ic,
- const DeviceInformation& deviceInfo);
++enum ElecType 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
*/
* 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.
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.
*/
{
set_cutoff_parameters(nbp, ic, listParams);
- map_interaction_types_to_gpu_kernel_flavors(ic, nbatParams.comb_rule, &(nbp->eeltype),
- &(nbp->vdwtype), deviceContext);
+ nbp->vdwType = nbnxmGpuPickVdwKernelType(ic, nbatParams.comb_rule);
- nbp->elecType = nbnxmGpuPickElectrostaticsKernelType(ic);
++ nbp->elecType = nbnxmGpuPickElectrostaticsKernelType(ic, deviceContext.deviceInfo());
if (ic->vdwtype == evdwPME)
{
}
/* generate table for PME */
nbp->coulomb_tab = nullptr;
- if (nbp->eeltype == eelTypeEWALD_TAB || nbp->eeltype == eelTypeEWALD_TAB_TWIN)
+ 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);
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;
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);
+ 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());
}
{
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);
+ copyToDeviceBuffer(&adat->shift_vec,
+ reinterpret_cast<const float*>(nbatom->shift_vec.data()),
+ 0,
+ SHIFTS * DIM,
+ deviceStream,
+ GpuApiCallBehavior::Async,
+ nullptr);
adat->bShiftVecUploaded = CL_TRUE;
}
}
allocateDeviceBuffer(&d_atdat->f, nalloc * DIM, deviceContext);
allocateDeviceBuffer(&d_atdat->xq, nalloc * (DIM + 1), deviceContext);
- if (useLjCombRule(nb->nbparam->vdwtype))
+ if (useLjCombRule(nb->nbparam->vdwType))
{
// Two Lennard-Jones parameters per atom
allocateDeviceBuffer(&d_atdat->lj_comb, nalloc * 2, deviceContext);
nbnxn_ocl_clear_f(nb, nalloc);
}
- if (useLjCombRule(nb->nbparam->vdwtype))
+ 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,
+ 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);
+ copyToDeviceBuffer(&d_atdat->atom_types,
+ nbat->params().type.data(),
+ 0,
+ natoms,
+ deviceStream,
+ GpuApiCallBehavior::Async,
+ bDoTime ? timers->atdat.fetchNextEvent() : nullptr);
}
if (bDoTime)
* 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.
if (pcrd.params.eGeom == epullgCYL)
{
- apply_forces_cyl_grp(&pull->dyna[coord], pcrd.spatialData.cyl_dev, masses, forces.force01,
- pcrd.scalarForce, -1, f, pull->nthreads);
+ apply_forces_cyl_grp(&pull->dyna[coord],
+ pcrd.spatialData.cyl_dev,
+ masses,
+ forces.force01,
+ pcrd.scalarForce,
+ -1,
+ f,
+ pull->nthreads);
/* Sum the force along the vector and the radial force */
dvec f_tot;
if (!pull->group[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(
+ &pull->group[pcrd.params.group[0]], masses, forces.force01, -1, f, pull->nthreads);
}
apply_forces_grp(&pull->group[pcrd.params.group[1]], masses, forces.force01, 1, f, pull->nthreads);
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(
+ &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);
}
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(
+ &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);
}
}
}
/* This function returns the distance based on coordinates xg and xref.
* Note that the pull coordinate struct pcrd is not modified.
+ *
+ * \param[in] pull The pull struct
+ * \param[in] pcrd The pull coordinate to compute a distance for
+ * \param[in] pbc The periodic boundary conditions
+ * \param[in] xg The coordinate of group 1
+ * \param[in] xref The coordinate of group 0
+ * \param[in] groupIndex0 The index of group 0 in the pcrd->params.group
+ * \param[in] groupIndex1 The index of group 1 in the pcrd->params.group
+ * \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,
const pull_coord_work_t* pcrd,
const t_pbc* pbc,
- dvec xg,
+ const dvec xg,
dvec xref,
- double max_dist2,
+ const int groupIndex0,
+ const int groupIndex1,
+ const double max_dist2,
dvec dr)
{
const pull_group_work_t* pgrp0 = &pull->group[pcrd->params.group[0]];
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[0],
- pcrd->params.group[1],
- 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 == epullgDIR
+ ? "You might want to consider using \"pull-geometry = "
+ "direction-periodic\" instead.\n"
+ : "");
}
if (pcrd->params.eGeom == epullgDIRPBC)
}
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]];
- 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 == epullgCYL ? pull->dyna[coord_ind].x : pgrp0->x,
++ 0,
++ 1,
+ md2,
+ spatialData.dr01);
if (pcrd->params.ngroup >= 4)
{
pgrp2 = &pull->group[pcrd->params.group[2]];
pgrp3 = &pull->group[pcrd->params.group[3]];
- low_get_pull_coord_dr(pull, pcrd, pbc, pgrp3->x, pgrp2->x, 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)
{
pgrp4 = &pull->group[pcrd->params.group[4]];
pgrp5 = &pull->group[pcrd->params.group[5]];
- low_get_pull_coord_dr(pull, pcrd, pbc, pgrp5->x, pgrp4->x, md2, spatialData.dr45);
+ low_get_pull_coord_dr(pull, pcrd, pbc, pgrp5->x, pgrp4->x, 4, 5, md2, spatialData.dr45);
}
}
{
gmx_fatal(FARGS,
"Pull reference distance for coordinate %d (%f) needs to be non-negative",
- coord_ind + 1, value_ref);
+ coord_ind + 1,
+ value_ref);
}
}
else if (pcrd->params.eGeom == epullgANGLE || pcrd->params.eGeom == epullgANGLEAXIS)
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)
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]], -1, unc_ij);
++ pull, pcrd, pbc, rnew[pcrd->params.group[1]], rnew[pcrd->params.group[0]], 0, 1, -1, unc_ij);
if (debug)
{
gmx_fatal(
FARGS,
"The pull constraint reference distance for group %zu is <= 0 (%f)",
- c, pcrd->value_ref);
+ c,
+ pcrd->value_ref);
}
{
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);
}
}
g0 = pcrd->params.group[0];
g1 = pcrd->params.group[1];
- low_get_pull_coord_dr(pull, pcrd, pbc, rnew[g1], rnew[g0], -1, tmp);
- low_get_pull_coord_dr(pull, pcrd, pbc, dr1, dr0, -1, 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));
+ 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 */
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]], -1, unc_ij);
++ pull, &coord, pbc, rnew[coord.params.group[1]], rnew[coord.params.group[0]], 0, 1, -1, unc_ij);
switch (coord.params.eGeom)
{
"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;
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;
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];
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,
+ epull_names[pcrd->params.eType],
+ epull_names[epullEXTERNAL]);
}
GMX_RELEASE_ASSERT(!pcrd->params.externalPotentialProvider.empty(),
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
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;
"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());
}
}
forceWithVirial->addVirialContribution(virial);
}
- apply_forces_coord(pull, coord_index, pullCoordForces, masses,
- as_rvec_array(forceWithVirial->force_.data()));
+ apply_forces_coord(
+ pull, coord_index, pullCoordForces, masses, as_rvec_array(forceWithVirial->force_.data()));
}
pull->numExternalPotentialsStillToBeAppliedThisStep--;
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)
}
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)
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->group.emplace_back(pull_params->group[i],
+ atomSets->add(pull_params->group[i].ind),
pull_params->bSetPbcRefToPrevStepCOM);
}
"%d 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);
+ c + 1,
+ pcrd->params.eGeom,
+ epullgNR - 1);
}
if (pcrd->params.eType == epullCONSTRAINT)
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[pcrd->params.eType],
+ epullg_names[pcrd->params.eGeom],
epull_names[epullUMBRELLA]);
}
if (pcrd->params.eType != epullEXTERNAL)
{
low_set_pull_coord_reference_value(
- pcrd, c,
- pcrd->params.init * pull_conversion_factor_userinput2internal(&pcrd->params));
+ pcrd, c, pcrd->params.init * pull_conversion_factor_userinput2internal(&pcrd->params));
}
else
{
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");
}
}
const auto& referenceGroup = pull->group[coord.params.group[0]];
- pull->dyna.emplace_back(referenceGroup.params, referenceGroup.atomSet,
- pull->params.bSetPbcRefToPrevStepCOM);
+ pull->dyna.emplace_back(
+ referenceGroup.params, referenceGroup.atomSet, pull->params.bSetPbcRefToPrevStepCOM);
}
}
{
/* 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);
}
* This file is part of the GROMACS molecular simulation package.
*
* Copyright (c) 2020 Research Organization for Information Science and Technology (RIST).
- * 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.
{
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)
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()
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)
// 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_ = svsel_f64(m, x.simdInternal_, svdup_n_f64(1.0));
+ x.simdInternal_ = svsel_f64(pg, x.simdInternal_, svdup_n_f64(1.0));
#endif
return { svreinterpret_f64_u64(svand_n_u64_z(
pg, svreinterpret_u64_f64(svrecpe_f64(x.simdInternal_)), 0xFFFFFFFFFFFFFFFF)) };
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)
{
* This file is part of the GROMACS molecular simulation package.
*
* Copyright (c) 2020 Research Organization for Information Science and Technology (RIST).
- * 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.
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));
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));
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));
alignas(GMX_SIMD_ALIGNMENT) double tvec[3 * GMX_SIMD_DOUBLE_WIDTH];
v = svcreate3_f64(v0.simdInternal_, v1.simdInternal_, v2.simdInternal_);
svst3_f64(pg, tvec, v);
+ #if GMX_SIMD_DOUBLE_WIDTH >= 3
pg = svwhilelt_b64(0, 3);
for (int i = 0; i < GMX_SIMD_DOUBLE_WIDTH; i++)
{
svfloat64_t t3 = svadd_f64_x(pg, t1, t2);
svst1_f64(pg, base + align * offset[i], t3);
}
+ #else
+ for (std::size_t i = 0; i < GMX_SIMD_DOUBLE_WIDTH; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ base[align * offset[i] + j] += tvec[i * 3 + j];
+ }
+ }
+ #endif
}
template<int align>
alignas(GMX_SIMD_ALIGNMENT) double tvec[3 * GMX_SIMD_DOUBLE_WIDTH];
v = svcreate3_f64(v0.simdInternal_, v1.simdInternal_, v2.simdInternal_);
svst3_f64(pg, tvec, v);
+ #if GMX_SIMD_DOUBLE_WIDTH >= 3
pg = svwhilelt_b64(0, 3);
for (int i = 0; i < GMX_SIMD_DOUBLE_WIDTH; i++)
{
svfloat64_t t3 = svsub_f64_x(pg, t1, t2);
svst1_f64(pg, base + align * offset[i], t3);
}
+ #else
+ for (std::size_t i = 0; i < GMX_SIMD_DOUBLE_WIDTH; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ base[align * offset[i] + j] -= tvec[i * 3 + j];
+ }
+ }
+ #endif
}
static inline void gmx_simdcall expandScalarsToTriplets(SimdDouble scalar,
sum[1] = svadda_f64(pg, 0.0, v1.simdInternal_);
sum[2] = svadda_f64(pg, 0.0, v2.simdInternal_);
sum[3] = svadda_f64(pg, 0.0, v3.simdInternal_);
- pg = svwhilelt_b64(0, 4);
- _m = svld1_f64(pg, m);
- _s = svld1_f64(pg, sum);
+ #if GMX_SIMD_DOUBLE_WIDTH >= 4
+ pg = svwhilelt_b64(0, 4);
+ _m = svld1_f64(pg, m);
+ _s = svld1_f64(pg, sum);
svst1_f64(pg, m, svadd_f64_x(pg, _m, _s));
return svadda_f64(pg, 0.0, _s);
+ #else
+ double res = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ m[i] += sum[i];
+ res += sum[i];
+ }
+ return res;
+ #endif
}
static inline SimdDouble gmx_simdcall loadDualHsimd(const double* m0, const double* m1)
sum[1] = svadda_f64(pg, 0.0, v0.simdInternal_);
sum[3] = svadda_f64(pg, 0.0, v1.simdInternal_);
+ #if GMX_SIMD_DOUBLE_WIDTH >= 4
pg = svwhilelt_b64(0, 4);
_m = svld1_f64(pg, m);
_s = svld1_f64(pg, sum);
svst1_f64(pg, m, svadd_f64_x(pg, _m, _s));
return svadda_f64(pg, 0.0, _s);
+ #else
+ double res = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ m[i] += sum[i];
+ res += sum[i];
+ }
+ return res;
+ #endif
}
template<int align>
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);
/*
* 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.
}
}
+ if (ngpu > 0 && (nrank_new % ngpu) != 0)
+ {
+ /* If we use GPUs, the number of ranks must be divisible by the number of GPUs,
+ * unless the GPUs are very different (and if they are, user should manually
+ * select the parallelization scheme).
+ * Rounding down the number of ranks, or setting it to ngpu, whichever is smaller.
+ * */
+ if (nrank_new > ngpu)
+ {
+ nrank_new = (nrank_new / ngpu) * ngpu;
+ }
+ else
+ {
+ nrank_new = ngpu;
+ }
+ }
+
nrank = nrank_new;
/* We reduced the number of tMPI ranks, which means we might violate
"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)
{
"%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);
}
}
}
//! 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->gpuIdsAvailable.c_str(),
+ hw_opt->userGpuTaskAssignment.c_str());
}
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)
"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)
"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);
}
}
"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)
"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);
}
}
* 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.
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)
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);
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:
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:
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;
case F_SETTLE:
writer->writeLineFormatted("doh=%15.8e, dhh=%15.8e", iparams.settle.doh, iparams.settle.dhh);
break;
+ case F_VSITE1: writer->ensureEmptyLine(); break;
case F_VSITE2: writer->writeLineFormatted("a=%15.8e", iparams.vsite.a); break;
case F_VSITE3:
case F_VSITE3FD:
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);
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__);
}
}
for (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]);
}
for (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);
}
}
}
* 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.
void printCopyright(gmx::TextWriter* writer)
{
+ // Contributors sorted alphabetically by last name
static const char* const Contributors[] = { "Andrey Alekseenko",
"Emile Apol",
"Rossen Apostolov",
"Aldert van Buuren",
"Rudi van Drunen",
"Anton Feenstra",
+ "Gilles Gouaillardet",
"Alan Gray",
"Gerrit Groenhof",
"Anca Hamuraru",
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."
};
#if GMX_DOUBLE
writer->writeLine("Precision: double");
#else
- writer->writeLine("Precision: single");
+ writer->writeLine("Precision: mixed");
#endif
writer->writeLine(formatString("Memory model: %u bit", static_cast<unsigned>(8 * sizeof(void*))));
#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
* 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));
#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
// 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))
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())
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_)
{
set(REGRESSIONTEST_URL https://gitlab.com/gromacs/gromacs-regressiontests/-/archive/${REGRESSIONTEST_BRANCH}/gromacs-regressiontests-${REGRESSIONTEST_BRANCH}.tar.gz)
# REGRESSIONTEST_PATH for dev trees is set later based on the dirname found in the tar
else()
- set(REGRESSIONTEST_URL http://ftp.gromacs.org/regressiontests/regressiontests-${REGRESSIONTEST_VERSION}.tar.gz)
+ set(REGRESSIONTEST_URL https://ftp.gromacs.org/regressiontests/regressiontests-${REGRESSIONTEST_VERSION}.tar.gz)
set(REGRESSIONTEST_PATH
"${CMAKE_CURRENT_BINARY_DIR}/regressiontests-${REGRESSIONTEST_VERSION}"
CACHE PATH "Path to auto-downloaded regressiontests" FORCE)
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()
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)
"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