From: Mark Abraham Date: Fri, 18 Dec 2020 07:23:07 +0000 (+0100) Subject: Merge branch release-2021 X-Git-Url: http://biod.pnpi.spb.ru/gitweb/?a=commitdiff_plain;h=252cfee1253d5c78e8eca9243b03ecdcc542ae1a;p=alexxy%2Fgromacs.git Merge branch release-2021 Some reformatting changes needed for the difference in .clang-format in the two branches --- 252cfee1253d5c78e8eca9243b03ecdcc542ae1a diff --cc admin/gitlab-ci/gromacs.gitlab-ci.yml index 939b51142d,582be7e014..b55d9fd323 --- a/admin/gitlab-ci/gromacs.gitlab-ci.yml +++ b/admin/gitlab-ci/gromacs.gitlab-ci.yml @@@ -230,8 -230,8 +230,8 @@@ gromacs:gcc-10:configure variables: CMAKE: /usr/local/cmake-3.13.0/bin/cmake CMAKE_SIMD_OPTIONS: "-DGMX_SIMD=AVX2_256" - CMAKE_EXTRA_OPTIONS: "-DGMX_EXTERNAL_CLFFT=ON" + CMAKE_EXTRA_OPTIONS: "-DGMX_EXTERNAL_CLFFT=ON -DGMX_INSTALL_LEGACY_API=ON" - COMPILER_MAJOR_VERSION: 7 + COMPILER_MAJOR_VERSION: 10 gromacs:clang-8-cuda-10.0:configure: extends: diff --cc admin/gitlab-ci/python-gmxapi02.gitlab-ci.yml index 8f0588cdb6,0000000000..fc267ecfa7 mode 100644,000000..100644 --- a/admin/gitlab-ci/python-gmxapi02.gitlab-ci.yml +++ b/admin/gitlab-ci/python-gmxapi02.gitlab-ci.yml @@@ -1,61 -1,0 +1,61 @@@ +# +# Jobs to test gmxapi client (Python) packages +# + - .gmxapi-0.2:gcc-7:gmx2021: ++.gmxapi-0.2:gcc-10:gmx2021: + extends: + - .variables:default + - .use-clang:base - image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7 ++ 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-7:build ++ - job: gromacs:gcc-10:build + artifacts: true + - gmxapi-0.2:gcc-7:gmx2021:py-3.6.10: ++gmxapi-0.2:gcc-10:gmx2021:py-3.6.10: + extends: - - .gmxapi-0.2:gcc-7:gmx2021 ++ - .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-7:gmx2021:py-3.7.7: ++gmxapi-0.2:gcc-10:gmx2021:py-3.7.7: + extends: - - .gmxapi-0.2:gcc-7:gmx2021 ++ - .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-7:gmx2021:py-3.8.2: ++gmxapi-0.2:gcc-10:gmx2021:py-3.8.2: + extends: - - .gmxapi-0.2:gcc-7:gmx2021 ++ - .gmxapi-0.2:gcc-10:gmx2021 + - .rules:merge-requests:release-2021 + variables: + VENVPATH: "/root/venv/py3.8" + PY_VER: "3.8.2" diff --cc admin/gitlab-ci/python-gmxapi03.gitlab-ci.yml index d88b74f4ce,0000000000..53a8605d01 mode 100644,000000..100644 --- a/admin/gitlab-ci/python-gmxapi03.gitlab-ci.yml +++ b/admin/gitlab-ci/python-gmxapi03.gitlab-ci.yml @@@ -1,53 -1,0 +1,53 @@@ +# +# Jobs to test gmxapi client (Python) packages +# + - .gmxapi-0.3:gcc-7:gmx2022: ++.gmxapi-0.3:gcc-10:gmx2022: + extends: + - .variables:default + - .use-clang:base - image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7 ++ image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10 + stage: test + variables: + KUBERNETES_CPU_LIMIT: 2 + KUBERNETES_CPU_REQUEST: 2 + KUBERNETES_MEMORY_LIMIT: 2Gi + KUBERNETES_MEMORY_REQUEST: 2Gi + PY_UNIT_TEST_XML: $CI_PROJECT_DIR/py-JUnitTestResults.xml + PY_MPI_UNIT_TEST_XML: $CI_PROJECT_DIR/py-mpi-JUnitTestResults.xml + PY_ACCEPTANCE_TEST_XML: $CI_PROJECT_DIR/gmxapi-acceptance-JUnitTestResults.xml + PY_MPI_ACCEPTANCE_TEST_XML: $CI_PROJECT_DIR/gmxapi-acceptance-mpi-JUnitTestResults.xml + script: + - source $INSTALL_DIR/bin/GMXRC + - source $VENVPATH/bin/activate && INSTALL_DIR=$PWD/$INSTALL_DIR OMP_NUM_THREADS=1 bash admin/ci-scripts/build-and-test-py-gmxapi-0.3.sh + artifacts: + reports: + junit: + - $PY_UNIT_TEST_XML + - $PY_MPI_UNIT_TEST_XML + - $PY_ACCEPTANCE_TEST_XML + - $PY_MPI_ACCEPTANCE_TEST_XML + when: always + expire_in: 1 week + tags: + - k8s-scilifelab + # The dependency means we need to use the same tag restriction as upstream. + needs: - - job: gromacs:gcc-7:build ++ - job: gromacs:gcc-10:build + artifacts: true + - gmxapi-0.3:gcc-7:gmx2022:py-3.7.7: ++gmxapi-0.3:gcc-10:gmx2022:py-3.7.7: + extends: - - .gmxapi-0.3:gcc-7:gmx2022 ++ - .gmxapi-0.3:gcc-10:gmx2022 + - .rules:merge-requests:master + variables: + VENVPATH: "/root/venv/py3.7" + PY_VER: "3.7.7" + - gmxapi-0.3:gcc-7:gmx2022:py-3.8.2: ++gmxapi-0.3:gcc-10:gmx2022:py-3.8.2: + extends: - - .gmxapi-0.3:gcc-7:gmx2022 ++ - .gmxapi-0.3:gcc-10:gmx2022 + - .rules:merge-requests:master + variables: + VENVPATH: "/root/venv/py3.8" + PY_VER: "3.8.2" diff --cc src/gromacs/gmxlib/nonbonded/nb_free_energy.cpp index 5c62efc57d,6573583c7e..3c9b933758 --- a/src/gromacs/gmxlib/nonbonded/nb_free_energy.cpp +++ b/src/gromacs/gmxlib/nonbonded/nb_free_energy.cpp @@@ -431,10 -435,15 +435,15 @@@ static void nb_free_energy_kernel(cons } npair_within_cutoff++; - if (rsq > rlistSquared) ++ if (rSq > rlistSquared) + { + numExcludedPairsBeyondRlist++; + } + - if (rsq > 0) + if (rSq > 0) { /* Note that unlike in the nbnxn kernels, we do not need - * to clamp the value of rsq before taking the invsqrt + * to clamp the value of rSq before taking the invsqrt * to avoid NaN in the LJ calculation, since here we do * not calculate LJ interactions when C6 and C12 are zero. */ @@@ -722,7 -731,7 +731,7 @@@ } } - if (vdwInteractionTypeIsEwald && r < rVdw) - if (vdwInteractionTypeIsEwald && (r < rvdw || !bPairIncluded)) ++ if (vdwInteractionTypeIsEwald && (r < rVdw || !bPairIncluded)) { /* See comment in the preamble. When using LJ-Ewald interactions * (unless we use a switch modifier) we subtract the reciprocal-space @@@ -839,6 -848,19 +848,20 @@@ */ #pragma omp atomic inc_nrnb(nrnb, eNR_NBKERNEL_FREE_ENERGY, nlist->nri * 12 + nlist->jindex[nri] * 150); + + if (numExcludedPairsBeyondRlist > 0) + { + gmx_fatal(FARGS, + "There are %d perturbed non-bonded pair interactions beyond the pair-list cutoff " + "of %g nm, which is not supported. This can happen because the system is " + "unstable or because intra-molecular interactions at long distances are " + "excluded. If the " + "latter is the case, you can try to increase nstlist or rlist to avoid this." + "The error is likely triggered by the use of couple-intramol=no " + "and the maximal distance in the decoupled molecule exceeding rlist.", - numExcludedPairsBeyondRlist, fr->rlist); ++ numExcludedPairsBeyondRlist, ++ fr->rlist); + } } typedef void (*KernelFunction)(const t_nblist* gmx_restrict nlist, diff --cc src/gromacs/mdlib/forcerec.cpp index c743b77c91,8d7eb27108..a0af9e6e7f --- a/src/gromacs/mdlib/forcerec.cpp +++ b/src/gromacs/mdlib/forcerec.cpp @@@ -771,14 -768,12 +772,14 @@@ void init_interaction_const_tables(FILE { if (EEL_PME_EWALD(ic->eeltype) || EVDW_PME(ic->vdwtype)) { - init_ewald_f_table(*ic, rlist, tableExtensionLength, ic->coulombEwaldTables.get(), - ic->vdwEwaldTables.get()); + init_ewald_f_table( - *ic, tableExtensionLength, ic->coulombEwaldTables.get(), ic->vdwEwaldTables.get()); ++ *ic, rlist, tableExtensionLength, ic->coulombEwaldTables.get(), ic->vdwEwaldTables.get()); if (fp != nullptr) { - fprintf(fp, "Initialized non-bonded Ewald tables, spacing: %.2e size: %zu\n\n", - 1 / ic->coulombEwaldTables->scale, ic->coulombEwaldTables->tableF.size()); + fprintf(fp, + "Initialized non-bonded Ewald tables, spacing: %.2e size: %zu\n\n", + 1 / ic->coulombEwaldTables->scale, + ic->coulombEwaldTables->tableF.size()); } } } diff --cc src/gromacs/modularsimulator/modularsimulator.cpp index f660dfd7af,2450711c10..f0bb4100b9 --- a/src/gromacs/modularsimulator/modularsimulator.cpp +++ b/src/gromacs/modularsimulator/modularsimulator.cpp @@@ -381,4 -388,32 +394,31 @@@ void ModularSimulator::checkInputForDis } } + void ModularSimulator::readCheckpointToTrxFrame(t_trxframe* fr, + ReadCheckpointDataHolder* readCheckpointDataHolder, + const CheckpointHeaderContents& checkpointHeaderContents) + { + GMX_RELEASE_ASSERT(checkpointHeaderContents.isModularSimulatorCheckpoint, + "ModularSimulator::readCheckpointToTrxFrame can only read checkpoints " + "written by modular simulator."); + fr->bStep = true; - fr->step = - int64_to_int(checkpointHeaderContents.step, "conversion of checkpoint to trajectory"); ++ fr->step = int64_to_int(checkpointHeaderContents.step, "conversion of checkpoint to trajectory"); + fr->bTime = true; + fr->time = checkpointHeaderContents.t; + + fr->bAtoms = false; + + StatePropagatorData::readCheckpointToTrxFrame( + fr, readCheckpointDataHolder->checkpointData(StatePropagatorData::checkpointID())); + if (readCheckpointDataHolder->keyExists(FreeEnergyPerturbationData::checkpointID())) + { + FreeEnergyPerturbationData::readCheckpointToTrxFrame( + fr, readCheckpointDataHolder->checkpointData(FreeEnergyPerturbationData::checkpointID())); + } + else + { + FreeEnergyPerturbationData::readCheckpointToTrxFrame(fr, std::nullopt); + } + } + } // namespace gmx diff --cc src/gromacs/modularsimulator/statepropagatordata.cpp index 28e4ef9a25,9269119321..866136a809 --- a/src/gromacs/modularsimulator/statepropagatordata.cpp +++ b/src/gromacs/modularsimulator/statepropagatordata.cpp @@@ -489,38 -482,47 +490,55 @@@ constexpr auto c_currentVersion = Check } // namespace template - void StatePropagatorData::Element::doCheckpointData(CheckpointData* checkpointData, - const t_commrec* cr) + void StatePropagatorData::doCheckpointData(CheckpointData* checkpointData) + { + checkpointVersion(checkpointData, "StatePropagatorData version", c_currentVersion); + checkpointData->scalar("numAtoms", &totalNumAtoms_); + + if (operation == CheckpointDataOperation::Read) + { + xGlobal_.resizeWithPadding(totalNumAtoms_); + vGlobal_.resizeWithPadding(totalNumAtoms_); + } + + checkpointData->arrayRef("positions", makeCheckpointArrayRef(xGlobal_)); + checkpointData->arrayRef("velocities", makeCheckpointArrayRef(vGlobal_)); + checkpointData->tensor("box", box_); + checkpointData->scalar("ddpCount", &ddpCount_); + checkpointData->scalar("ddpCountCgGl", &ddpCountCgGl_); + checkpointData->arrayRef("cgGl", makeCheckpointArrayRef(cgGl_)); + } + + void StatePropagatorData::Element::saveCheckpointState(std::optional checkpointData, + const t_commrec* cr) { - ArrayRef xGlobalRef; - ArrayRef vGlobalRef; if (DOMAINDECOMP(cr)) { - if (MASTER(cr)) - { - xGlobalRef = statePropagatorData_->xGlobal_; - vGlobalRef = statePropagatorData_->vGlobal_; - } - if (operation == CheckpointDataOperation::Write) - { - dd_collect_vec(cr->dd, - statePropagatorData_->ddpCount_, - statePropagatorData_->ddpCountCgGl_, - statePropagatorData_->cgGl_, - statePropagatorData_->x_, - xGlobalRef); - dd_collect_vec(cr->dd, - statePropagatorData_->ddpCount_, - statePropagatorData_->ddpCountCgGl_, - statePropagatorData_->cgGl_, - statePropagatorData_->v_, - vGlobalRef); - } + // Collect state from all ranks into global vectors - dd_collect_vec(cr->dd, statePropagatorData_->ddpCount_, statePropagatorData_->ddpCountCgGl_, - statePropagatorData_->cgGl_, statePropagatorData_->x_, ++ dd_collect_vec(cr->dd, ++ statePropagatorData_->ddpCount_, ++ statePropagatorData_->ddpCountCgGl_, ++ statePropagatorData_->cgGl_, ++ statePropagatorData_->x_, + statePropagatorData_->xGlobal_); - dd_collect_vec(cr->dd, statePropagatorData_->ddpCount_, statePropagatorData_->ddpCountCgGl_, - statePropagatorData_->cgGl_, statePropagatorData_->v_, ++ dd_collect_vec(cr->dd, ++ statePropagatorData_->ddpCount_, ++ statePropagatorData_->ddpCountCgGl_, ++ statePropagatorData_->cgGl_, ++ statePropagatorData_->v_, + statePropagatorData_->vGlobal_); } else { - xGlobalRef = statePropagatorData_->x_; - vGlobalRef = statePropagatorData_->v_; + // Everything is local - copy local vectors into global ones + statePropagatorData_->xGlobal_.resizeWithPadding(statePropagatorData_->totalNumAtoms()); + statePropagatorData_->vGlobal_.resizeWithPadding(statePropagatorData_->totalNumAtoms()); - std::copy(statePropagatorData_->x_.begin(), statePropagatorData_->x_.end(), ++ std::copy(statePropagatorData_->x_.begin(), ++ statePropagatorData_->x_.end(), + statePropagatorData_->xGlobal_.begin()); - std::copy(statePropagatorData_->v_.begin(), statePropagatorData_->v_.end(), ++ std::copy(statePropagatorData_->v_.begin(), ++ statePropagatorData_->v_.end(), + statePropagatorData_->vGlobal_.begin()); } if (MASTER(cr)) { @@@ -573,14 -563,21 +579,26 @@@ void StatePropagatorData::Element::rest // Copy data to global state to be distributed by DD at setup stage if (DOMAINDECOMP(cr) && MASTER(cr)) { - updateGlobalState(statePropagatorData_->globalState_, statePropagatorData_->xGlobal_, - statePropagatorData_->vGlobal_, statePropagatorData_->box_, - statePropagatorData_->ddpCount_, statePropagatorData_->ddpCountCgGl_, + updateGlobalState(statePropagatorData_->globalState_, + statePropagatorData_->xGlobal_, + statePropagatorData_->vGlobal_, + statePropagatorData_->box_, + statePropagatorData_->ddpCount_, + statePropagatorData_->ddpCountCgGl_, statePropagatorData_->cgGl_); } + // Everything is local - copy global vectors to local ones + if (!DOMAINDECOMP(cr)) + { + statePropagatorData_->x_.resizeWithPadding(statePropagatorData_->totalNumAtoms_); + statePropagatorData_->v_.resizeWithPadding(statePropagatorData_->totalNumAtoms_); - std::copy(statePropagatorData_->xGlobal_.begin(), statePropagatorData_->xGlobal_.end(), ++ std::copy(statePropagatorData_->xGlobal_.begin(), ++ statePropagatorData_->xGlobal_.end(), + statePropagatorData_->x_.begin()); - std::copy(statePropagatorData_->vGlobal_.begin(), statePropagatorData_->vGlobal_.end(), ++ std::copy(statePropagatorData_->vGlobal_.begin(), ++ statePropagatorData_->vGlobal_.end(), + statePropagatorData_->v_.begin()); + } } const std::string& StatePropagatorData::Element::clientID() diff --cc src/gromacs/simd/impl_arm_sve/impl_arm_sve_simd_double.h index 542d642f49,c650ad276e..2e5e15850d --- a/src/gromacs/simd/impl_arm_sve/impl_arm_sve_simd_double.h +++ b/src/gromacs/simd/impl_arm_sve/impl_arm_sve_simd_double.h @@@ -388,13 -390,20 +388,21 @@@ static inline SimdDouble gmx_simdcall f iExponent = svsub_s64_x( pg, svreinterpret_s64_u64(svlsr_n_u64_x(pg, svreinterpret_u64_s64(iExponent), 52)), exponentBias); - exponent->simdInternal_ = iExponent; - return { svreinterpret_f64_s64( - 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))) }; ++ svreinterpret_s64_f64(half))); + + if (opt == MathOptimization::Safe) + { + svbool_t valueIsZero = svcmpeq_n_f64(pg, value.simdInternal_, 0.0); + iExponent = svsel_s64(valueIsZero, svdup_s64(0), iExponent); + result = svsel_f64(valueIsZero, value.simdInternal_, result); + } + + exponent->simdInternal_ = iExponent; + return { result }; } template diff --cc src/gromacs/simd/impl_arm_sve/impl_arm_sve_simd_float.h index a7f2737c27,1171124f19..2945ea66a0 --- a/src/gromacs/simd/impl_arm_sve/impl_arm_sve_simd_float.h +++ b/src/gromacs/simd/impl_arm_sve/impl_arm_sve_simd_float.h @@@ -392,12 -392,21 +392,21 @@@ static inline SimdFloat gmx_simdcall fr iExponent = svand_s32_x(pg, svreinterpret_s32_f32(value.simdInternal_), exponentMask); iExponent = svsub_s32_x( pg, svreinterpret_s32_u32(svlsr_n_u32_x(pg, svreinterpret_u32_s32(iExponent), 23)), exponentBias); - exponent->simdInternal_ = iExponent; - return { svreinterpret_f32_s32( - - svfloat32_t result = svreinterpret_f32_s32(svorr_s32_x( - pg, svand_s32_x(pg, svreinterpret_s32_f32(value.simdInternal_), mantissaMask), - svreinterpret_s32_f32(half))); ++ svfloat32_t result = svreinterpret_f32_s32( + svorr_s32_x(pg, + svand_s32_x(pg, svreinterpret_s32_f32(value.simdInternal_), mantissaMask), - svreinterpret_s32_f32(half))) }; ++ svreinterpret_s32_f32(half))); + + if (opt == MathOptimization::Safe) + { + svbool_t valueIsZero = svcmpeq_n_f32(pg, value.simdInternal_, 0.0F); + iExponent = svsel_s32(valueIsZero, svdup_s32(0), iExponent); + result = svsel_f32(valueIsZero, value.simdInternal_, result); + } + + exponent->simdInternal_ = iExponent; + return { result }; } template diff --cc src/gromacs/utility/keyvaluetree.cpp index ab7a55ea54,adc754772e..24fa2b3fd4 --- a/src/gromacs/utility/keyvaluetree.cpp +++ b/src/gromacs/utility/keyvaluetree.cpp @@@ -113,6 -113,21 +113,22 @@@ void dumpKeyValueTree(TextWriter* write dumpKeyValueTree(writer, value.asObject()); writer->wrapperSettings().setIndent(oldIndent); } + else if (value.isArray() - && std::all_of(value.asArray().values().begin(), value.asArray().values().end(), ++ && std::all_of(value.asArray().values().begin(), ++ value.asArray().values().end(), + [](const auto& elem) { return elem.isObject(); })) + { + // Array containing only objects + writer->writeString(prop.key()); + writer->writeLine(":"); + int oldIndent = writer->wrapperSettings().indent(); + writer->wrapperSettings().setIndent(oldIndent + 2); + for (const auto& elem : value.asArray().values()) + { + dumpKeyValueTree(writer, elem.asObject()); + } + writer->wrapperSettings().setIndent(oldIndent); + } else { int indent = writer->wrapperSettings().indent(); diff --cc src/programs/CMakeLists.txt index 56a21bd394,860729a26a..63c595a630 --- a/src/programs/CMakeLists.txt +++ b/src/programs/CMakeLists.txt @@@ -51,23 -47,20 +51,24 @@@ if(GMX_FAHCORE # may break some generators, according to CMake documentation. If # so, we can consider adding some dummy file to make it work. add_library(fahcore $) - target_link_libraries(fahcore PRIVATE ${GMX_COMMON_LIBRARIES}) + target_link_libraries(fahcore PRIVATE ${GMX_COMMON_LIBRARIES} legacy_api) elseif(GMX_BUILD_MDRUN_ONLY) + message(STATUS "The mdrun-only build is deprecated") - add_executable(mdrun $ mdrun_main.cpp) - gmx_target_compile_options(mdrun) - target_include_directories(mdrun SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/src/external/thread_mpi/include) - target_compile_definitions(mdrun PRIVATE HAVE_CONFIG_H) - target_link_libraries(mdrun libgromacs - ${GMX_COMMON_LIBRARIES} - ${GMX_EXE_LINKER_FLAGS}) + add_executable(mdrun-only $ mdrun_main.cpp) + gmx_target_compile_options(mdrun-only) + target_include_directories(mdrun-only SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/src/external/thread_mpi/include) + target_compile_definitions(mdrun-only PRIVATE HAVE_CONFIG_H) + target_link_libraries(mdrun-only PRIVATE + common + legacy_modules + libgromacs + ${GMX_COMMON_LIBRARIES} + ${GMX_EXE_LINKER_FLAGS} + ) set(BINARY_NAME "mdrun${GMX_BINARY_SUFFIX}") - set_target_properties(mdrun PROPERTIES + set_target_properties(mdrun-only PROPERTIES OUTPUT_NAME "${BINARY_NAME}") - install(TARGETS mdrun DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT mdrun) + install(TARGETS mdrun-only DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT mdrun-only) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/gmx-completion-${BINARY_NAME}.bash "complete -o nospace -F _gmx_mdrun_compl ${BINARY_NAME}") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/gmx-completion-${BINARY_NAME}.bash diff --cc src/programs/mdrun/tests/CMakeLists.txt index 4a7774237f,e4eccebd69..357882bb48 --- a/src/programs/mdrun/tests/CMakeLists.txt +++ b/src/programs/mdrun/tests/CMakeLists.txt @@@ -231,6 -230,18 +231,20 @@@ gmx_add_gtest_executable(${exename $ ) target_link_libraries(${exename} PRIVATE mdrun_test_infrastructure) +# TODO: Link specific modules: topology +target_link_libraries(${exename} PRIVATE legacy_modules) gmx_register_gtest_test(${testname} ${exename} OPENMP_THREADS 2 INTEGRATION_TEST IGNORE_LEAKS) + + # End-to-end tests comparing different simulator code paths + set(testname "MdrunSimulatorComparison") + set(exename "mdrun-simulator-comparison-test") + + gmx_add_gtest_executable(${exename} + CPP_SOURCE_FILES + # files with code for tests + simulator.cpp + # pseudo-library for code for mdrun + $ + ) + target_link_libraries(${exename} PRIVATE mdrun_test_infrastructure) + gmx_register_gtest_test(${testname} ${exename} OPENMP_THREADS 2 INTEGRATION_TEST IGNORE_LEAKS) diff --cc src/programs/mdrun/tests/checkpoint.cpp index 0000000000,dcee1703fe..2ddd809420 mode 000000,100644..100644 --- a/src/programs/mdrun/tests/checkpoint.cpp +++ b/src/programs/mdrun/tests/checkpoint.cpp @@@ -1,0 -1,171 +1,174 @@@ + /* + * This file is part of the GROMACS molecular simulation package. + * + * Copyright (c) 2020, by the GROMACS development team, led by + * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, + * and including many others, as listed in the AUTHORS file in the + * top-level source directory and at http://www.gromacs.org. + * + * GROMACS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * GROMACS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with GROMACS; if not, see + * http://www.gnu.org/licenses, or write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * If you want to redistribute modifications to GROMACS, please + * consider that scientific software is very special. Version + * control is crucial - bugs must be traceable. We will be happy to + * consider code for inclusion in the official distribution, but + * derived work must not be called official GROMACS. Details are found + * in the README & COPYING files - if they are missing, get the + * official version at http://www.gromacs.org. + * + * To help us fund GROMACS development, we humbly ask that you cite + * the research papers on the package. Check out http://www.gromacs.org. + */ + + /*! \internal \file + * \brief Tests for checkpoint writing sanity checks + * + * Checks that final checkpoint is equal to final trajectory output. + * + * \author Pascal Merz + * \ingroup module_mdrun_integration_tests + */ + #include "gmxpre.h" + + #include "config.h" + + #include "gromacs/utility/strconvert.h" + #include "gromacs/utility/stringutil.h" + + #include "testutils/simulationdatabase.h" + + #include "moduletest.h" + #include "simulatorcomparison.h" + #include "trajectoryreader.h" + + namespace gmx::test + { + namespace + { + + class CheckpointCoordinatesSanityChecks : + public MdrunTestFixture, + public ::testing::WithParamInterface> + { + public: + void runSimulation(MdpFieldValues mdpFieldValues, + int numSteps, + const std::string& trrFileName, + const std::string& cptFileName) + { + mdpFieldValues["nsteps"] = toString(numSteps); + // Trajectories have the initial and the last frame + mdpFieldValues["nstxout"] = toString(numSteps); + mdpFieldValues["nstvout"] = toString(numSteps); + mdpFieldValues["nstfout"] = toString(0); + + // Run grompp + runner_.useStringAsMdpFile(prepareMdpFileContents(mdpFieldValues)); + runGrompp(&runner_); + + // Do first mdrun + runner_.fullPrecisionTrajectoryFileName_ = trrFileName; + runMdrun(&runner_, { { "-cpo", cptFileName } }); + } + + static void compareCptAndTrr(const std::string& trrFileName, + const std::string& cptFileName, + const TrajectoryComparison& trajectoryComparison) + { + TrajectoryFrameReader trrReader(trrFileName); + TrajectoryFrameReader cptReader(cptFileName); + // Checkpoint has at least one frame + EXPECT_TRUE(cptReader.readNextFrame()); + // Trajectory has at least two frames + EXPECT_TRUE(trrReader.readNextFrame()); + EXPECT_NO_THROW(trrReader.frame()); + EXPECT_TRUE(trrReader.readNextFrame()); + + // Now compare frames + trajectoryComparison(cptReader.frame(), trrReader.frame()); + + // Files had exactly 1 / 2 frames + EXPECT_FALSE(cptReader.readNextFrame()); + EXPECT_FALSE(trrReader.readNextFrame()); + } + }; + + TEST_P(CheckpointCoordinatesSanityChecks, WithinTolerances) + { + const auto& params = GetParam(); + const auto& simulationName = std::get<0>(params); + const auto& integrator = std::get<1>(params); + const auto& temperatureCoupling = std::get<2>(params); + const auto& pressureCoupling = std::get<3>(params); + + // Specify how trajectory frame matching must work. + TrajectoryFrameMatchSettings trajectoryMatchSettings{ true, + true, + true, + ComparisonConditions::MustCompare, + ComparisonConditions::MustCompare, + ComparisonConditions::NoComparison, + MaxNumFrames::compareAllFrames() }; + if (integrator == "md-vv") + { + // When using md-vv and modular simulator, the velocities are expected to be off by + // 1/2 dt between checkpoint (top of the loop) and trajectory (full time step state) + trajectoryMatchSettings.velocitiesComparison = ComparisonConditions::NoComparison; + } - const TrajectoryTolerances trajectoryTolerances{ defaultRealTolerance(), defaultRealTolerance(), - defaultRealTolerance(), defaultRealTolerance() }; ++ const TrajectoryTolerances trajectoryTolerances{ ++ defaultRealTolerance(), defaultRealTolerance(), defaultRealTolerance(), defaultRealTolerance() ++ }; + + const auto mdpFieldValues = + prepareMdpFieldValues(simulationName, integrator, temperatureCoupling, pressureCoupling); + runner_.useTopGroAndNdxFromDatabase(simulationName); + // Set file names + const auto cptFileName = fileManager_.getTemporaryFilePath(".cpt"); + const auto trrFileName = fileManager_.getTemporaryFilePath(".trr"); + + SCOPED_TRACE(formatString( + "Checking the sanity of the checkpointed coordinates using system '%s' " + "with integrator '%s', '%s' temperature coupling, and '%s' pressure coupling ", - simulationName.c_str(), integrator.c_str(), temperatureCoupling.c_str(), ++ simulationName.c_str(), ++ integrator.c_str(), ++ temperatureCoupling.c_str(), + pressureCoupling.c_str())); + + SCOPED_TRACE("End of trajectory sanity"); + // Running a few steps - we expect the checkpoint to be equal + // to the final configuration + runSimulation(mdpFieldValues, 16, trrFileName, cptFileName); + compareCptAndTrr(trrFileName, cptFileName, { trajectoryMatchSettings, trajectoryTolerances }); + } + + #if !GMX_GPU_OPENCL + INSTANTIATE_TEST_CASE_P(CheckpointCoordinatesAreSane, + CheckpointCoordinatesSanityChecks, + ::testing::Combine(::testing::Values("spc2"), + ::testing::Values("md", "md-vv"), + ::testing::Values("no"), + ::testing::Values("no"))); + #else + INSTANTIATE_TEST_CASE_P(DISABLED_CheckpointCoordinatesAreSane, + CheckpointCoordinatesSanityChecks, + ::testing::Combine(::testing::Values("spc2"), + ::testing::Values("md", "md-vv"), + ::testing::Values("no"), + ::testing::Values("no"))); + #endif + + } // namespace + } // namespace gmx::test diff --cc src/programs/mdrun/tests/freeenergy.cpp index 6c39160bf3,3159e3db4e..9072e7b98e --- a/src/programs/mdrun/tests/freeenergy.cpp +++ b/src/programs/mdrun/tests/freeenergy.cpp @@@ -95,8 -95,18 +95,19 @@@ TEST_P(FreeEnergyReferenceTest, WithinT const auto maxNumWarnings = std::get<1>(GetParam()); const auto& interactionsList = std::get<2>(GetParam()); - // TODO In similar tests, we are checking if the tests - // can be run with the number of MPI ranks available + // As these tests check reproducibility, we restrict the maximum number + // of ranks to allow us to keep the tolerances tight. See also #3741. + const int numRanksAvailable = getNumberOfTestMpiRanks(); + constexpr int maxNumRanks = 8; + if (numRanksAvailable > maxNumRanks) + { + fprintf(stdout, + "The FEP tests cannot run with %d ranks.\n" + "The maximum number of ranks supported is %d.", - numRanksAvailable, maxNumRanks); ++ numRanksAvailable, ++ maxNumRanks); + return; + } SCOPED_TRACE(formatString("Comparing FEP simulation '%s' to reference", simulationName.c_str())); @@@ -152,15 -171,21 +172,21 @@@ // Check that the energies agree with the refdata within tolerance. checkEnergiesAgainstReferenceData(simulationEdrFileName, energyTermsToCompare, &rootChecker); // Check that the trajectories agree with the refdata within tolerance. - if (testAllTrajectoryFrames) + if (testTwoTrajectoryFrames) { - checkTrajectoryAgainstReferenceData(simulationTrajectoryFileName, trajectoryComparison, &rootChecker); - checkTrajectoryAgainstReferenceData(simulationTrajectoryFileName, trajectoryComparison, - &rootChecker, MaxNumFrames(2)); ++ checkTrajectoryAgainstReferenceData( ++ simulationTrajectoryFileName, trajectoryComparison, &rootChecker, MaxNumFrames(2)); } - else + else if (testOneTrajectoryFrame) { - checkTrajectoryAgainstReferenceData(simulationTrajectoryFileName, trajectoryComparison, - &rootChecker, MaxNumFrames(1)); + checkTrajectoryAgainstReferenceData( + simulationTrajectoryFileName, trajectoryComparison, &rootChecker, MaxNumFrames(1)); } + else + { - checkTrajectoryAgainstReferenceData(simulationTrajectoryFileName, trajectoryComparison, - &rootChecker, MaxNumFrames(0)); ++ checkTrajectoryAgainstReferenceData( ++ simulationTrajectoryFileName, trajectoryComparison, &rootChecker, MaxNumFrames(0)); + } if (File::exists(simulationDhdlFileName, File::returnFalseOnError)) { TextInputFile dhdlFile(simulationDhdlFileName); diff --cc src/programs/mdrun/tests/simulator.cpp index b8aec654a7,693f22c773..65418e8c89 --- a/src/programs/mdrun/tests/simulator.cpp +++ b/src/programs/mdrun/tests/simulator.cpp @@@ -116,18 -123,15 +124,18 @@@ TEST_P(SimulatorComparisonTest, WithinT "Comparing two simulations of '%s' " "with integrator '%s', '%s' temperature coupling, and '%s' pressure coupling " "switching environment variable '%s'", - simulationName.c_str(), integrator.c_str(), tcoupling.c_str(), pcoupling.c_str(), + simulationName.c_str(), + integrator.c_str(), + tcoupling.c_str(), + pcoupling.c_str(), environmentVariable.c_str())); - const auto mdpFieldValues = prepareMdpFieldValues(simulationName.c_str(), integrator.c_str(), - tcoupling.c_str(), pcoupling.c_str()); + const auto mdpFieldValues = prepareMdpFieldValues( + simulationName.c_str(), integrator.c_str(), tcoupling.c_str(), pcoupling.c_str()); EnergyTermsToCompare energyTermsToCompare{ { - { interaction_function[F_EPOT].longname, relativeToleranceAsPrecisionDependentUlp(10.0, 100, 80) }, - { interaction_function[F_EKIN].longname, relativeToleranceAsPrecisionDependentUlp(60.0, 100, 80) }, + { interaction_function[F_EPOT].longname, relativeToleranceAsPrecisionDependentUlp(60.0, 200, 160) }, + { interaction_function[F_EKIN].longname, relativeToleranceAsPrecisionDependentUlp(60.0, 200, 160) }, { interaction_function[F_PRES].longname, relativeToleranceAsPrecisionDependentFloatingPoint(10.0, 0.01, 0.001) }, } };