From 83297a1071e16cb5002766cabdb773df76cfe411 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 27 Jul 2024 21:06:52 -0400 Subject: [PATCH] extend force style testers for bonded interactions to check KOKKOS/OpenMP selectively imported from PR #4190 by @alphataubio --- unittest/force-styles/test_angle_style.cpp | 120 ++++++++++++++++++ unittest/force-styles/test_bond_style.cpp | 106 ++++++++++++++++ unittest/force-styles/test_dihedral_style.cpp | 106 ++++++++++++++++ unittest/force-styles/test_improper_style.cpp | 102 +++++++++++++++ 4 files changed, 434 insertions(+) diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index e2b76cc7b6..e706cc11ac 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -530,6 +530,126 @@ TEST(AngleStyle, omp) if (!verbose) ::testing::internal::GetCapturedStdout(); }; +TEST(AngleStyle, kokkos_omp) +{ + if (!LAMMPS::is_installed_pkg("KOKKOS")) GTEST_SKIP(); + if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); + if (!Info::has_accelerator_feature("KOKKOS", "api", "openmp")) GTEST_SKIP(); + + LAMMPS::argv args = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite", + "-k", "on", "t", "4", "-sf", "kk"}; + + ::testing::internal::CaptureStdout(); + LAMMPS *lmp = init_lammps(args, test_config, true); + + std::string output = ::testing::internal::GetCapturedStdout(); + if (verbose) std::cout << output; + + if (!lmp) { + std::cerr << "One or more prerequisite styles with /kk suffix\n" + "are not available in this LAMMPS configuration:\n"; + for (auto &prerequisite : test_config.prerequisites) { + std::cerr << prerequisite.first << "_style " << prerequisite.second << "\n"; + } + GTEST_SKIP(); + } + + EXPECT_THAT(output, StartsWith("LAMMPS (")); + EXPECT_THAT(output, HasSubstr("Loop time")); + + // abort if running in parallel and not all atoms are local + const int nlocal = lmp->atom->nlocal; + ASSERT_EQ(lmp->atom->natoms, nlocal); + + // relax error a bit for KOKKOS package + double epsilon = 5.0 * test_config.epsilon; + + ErrorStats stats; + auto angle = lmp->force->angle; + + EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("init_stress (newton on)", angle->virial, test_config.init_stress, epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "init_energy stats, newton on: " << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + run_lammps(lmp); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_FORCES("run_forces (newton on)", lmp->atom, test_config.run_forces, 10 * epsilon); + EXPECT_STRESS("run_stress (newton on)", angle->virial, test_config.run_stress, epsilon); + + stats.reset(); + int id = lmp->modify->find_compute("sum"); + double energy = lmp->modify->compute[id]->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.run_energy, epsilon); + EXPECT_FP_LE_WITH_EPS(angle->energy, energy, epsilon); + if (print_stats) std::cerr << "run_energy stats, newton on: " << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + cleanup_lammps(lmp, test_config); + lmp = init_lammps(args, test_config, false); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + // skip over these tests if newton bond is forced to be on + if (lmp->force->newton_bond == 0) { + angle = lmp->force->angle; + + EXPECT_FORCES("init_forces (newton off)", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("init_stress (newton off)", angle->virial, test_config.init_stress, + 2 * epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "init_energy stats, newton off:" << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + run_lammps(lmp); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_FORCES("run_forces (newton off)", lmp->atom, test_config.run_forces, 10 * epsilon); + EXPECT_STRESS("run_stress (newton off)", angle->virial, test_config.run_stress, epsilon); + + stats.reset(); + id = lmp->modify->find_compute("sum"); + energy = lmp->modify->compute[id]->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.run_energy, epsilon); + EXPECT_FP_LE_WITH_EPS(angle->energy, energy, epsilon); + if (print_stats) std::cerr << "run_energy stats, newton off:" << stats << std::endl; + } + + if (!verbose) ::testing::internal::CaptureStdout(); + restart_lammps(lmp, test_config); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + angle = lmp->force->angle; + EXPECT_FORCES("restart_forces", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("restart_stress", angle->virial, test_config.init_stress, epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "restart_energy stats:" << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + data_lammps(lmp, test_config); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + angle = lmp->force->angle; + EXPECT_FORCES("data_forces", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("data_stress", angle->virial, test_config.init_stress, epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "data_energy stats:" << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + cleanup_lammps(lmp, test_config); + if (!verbose) ::testing::internal::GetCapturedStdout(); +}; + + TEST(AngleStyle, numdiff) { if (!LAMMPS::is_installed_pkg("EXTRA-FIX")) GTEST_SKIP(); diff --git a/unittest/force-styles/test_bond_style.cpp b/unittest/force-styles/test_bond_style.cpp index d2523ff51d..81b105259d 100644 --- a/unittest/force-styles/test_bond_style.cpp +++ b/unittest/force-styles/test_bond_style.cpp @@ -532,6 +532,112 @@ TEST(BondStyle, omp) if (!verbose) ::testing::internal::GetCapturedStdout(); }; +TEST(BondStyle, kokkos_omp) +{ + if (!LAMMPS::is_installed_pkg("KOKKOS")) GTEST_SKIP(); + if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); + if (!Info::has_accelerator_feature("KOKKOS", "api", "openmp")) GTEST_SKIP(); + + LAMMPS::argv args = {"BondStyle", "-log", "none", "-echo", "screen", "-nocite", + "-k", "on", "t", "4", "-sf", "kk"}; + + ::testing::internal::CaptureStdout(); + LAMMPS *lmp = init_lammps(args, test_config, true); + + std::string output = ::testing::internal::GetCapturedStdout(); + if (verbose) std::cout << output; + + if (!lmp) { + std::cerr << "One or more prerequisite styles with /kk suffix\n" + "are not available in this LAMMPS configuration:\n"; + for (auto &prerequisite : test_config.prerequisites) { + std::cerr << prerequisite.first << "_style " << prerequisite.second << "\n"; + } + GTEST_SKIP(); + } + + EXPECT_THAT(output, StartsWith("LAMMPS (")); + EXPECT_THAT(output, HasSubstr("Loop time")); + + // abort if running in parallel and not all atoms are local + const int nlocal = lmp->atom->nlocal; + ASSERT_EQ(lmp->atom->natoms, nlocal); + + // relax error a bit for KOKKOS package + double epsilon = 5.0 * test_config.epsilon; + + ErrorStats stats; + auto bond = lmp->force->bond; + + EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("init_stress (newton on)", bond->virial, test_config.init_stress, 10 * epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(bond->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "init_energy stats, newton on: " << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + run_lammps(lmp); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_FORCES("run_forces (newton on)", lmp->atom, test_config.run_forces, 10 * epsilon); + EXPECT_STRESS("run_stress (newton on)", bond->virial, test_config.run_stress, 10 * epsilon); + + stats.reset(); + int id = lmp->modify->find_compute("sum"); + double energy = lmp->modify->compute[id]->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(bond->energy, test_config.run_energy, epsilon); + + // FIXME: this is currently broken ??? for KOKKOS with bond style hybrid + // needs to be fixed in the main code somewhere. Not sure where, though. + //if (test_config.bond_style.substr(0, 6) != "hybrid") + // EXPECT_FP_LE_WITH_EPS(bond->energy, energy, epsilon); + + if (print_stats) std::cerr << "run_energy stats, newton on: " << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + cleanup_lammps(lmp, test_config); + lmp = init_lammps(args, test_config, false); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + // skip over these tests if newton bond is forced to be on + if (lmp->force->newton_bond == 0) { + bond = lmp->force->bond; + + EXPECT_FORCES("init_forces (newton off)", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("init_stress (newton off)", bond->virial, test_config.init_stress, + 10 * epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(bond->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "init_energy stats, newton off:" << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + run_lammps(lmp); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_FORCES("run_forces (newton off)", lmp->atom, test_config.run_forces, 10 * epsilon); + EXPECT_STRESS("run_stress (newton off)", bond->virial, test_config.run_stress, + 10 * epsilon); + + stats.reset(); + id = lmp->modify->find_compute("sum"); + energy = lmp->modify->compute[id]->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(bond->energy, test_config.run_energy, epsilon); + + // FIXME: this is currently broken ??? for KOKKOS with bond style hybrid + // needs to be fixed in the main code somewhere. Not sure where, though. + //if (test_config.bond_style.substr(0, 6) != "hybrid") + // EXPECT_FP_LE_WITH_EPS(bond->energy, energy, epsilon); + + if (print_stats) std::cerr << "run_energy stats, newton off:" << stats << std::endl; + } + + if (!verbose) ::testing::internal::CaptureStdout(); + cleanup_lammps(lmp, test_config); + if (!verbose) ::testing::internal::GetCapturedStdout(); +}; + TEST(BondStyle, numdiff) { if (!LAMMPS::is_installed_pkg("EXTRA-FIX")) GTEST_SKIP(); diff --git a/unittest/force-styles/test_dihedral_style.cpp b/unittest/force-styles/test_dihedral_style.cpp index e6c34843c3..324745cc41 100644 --- a/unittest/force-styles/test_dihedral_style.cpp +++ b/unittest/force-styles/test_dihedral_style.cpp @@ -534,6 +534,112 @@ TEST(DihedralStyle, omp) if (!verbose) ::testing::internal::GetCapturedStdout(); }; +TEST(DihedralStyle, kokkos_omp) +{ + if (!LAMMPS::is_installed_pkg("KOKKOS")) GTEST_SKIP(); + if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); + if (!Info::has_accelerator_feature("KOKKOS", "api", "openmp")) GTEST_SKIP(); + + LAMMPS::argv args = {"DihedralStyle", "-log", "none", "-echo", "screen", "-nocite", + "-k", "on", "t", "4", "-sf", "kk"}; + + ::testing::internal::CaptureStdout(); + LAMMPS *lmp = init_lammps(args, test_config, true); + + std::string output = ::testing::internal::GetCapturedStdout(); + if (verbose) std::cout << output; + + if (!lmp) { + std::cerr << "One or more prerequisite styles with /kk suffix\n" + "are not available in this LAMMPS configuration:\n"; + for (auto &prerequisite : test_config.prerequisites) { + std::cerr << prerequisite.first << "_style " << prerequisite.second << "\n"; + } + GTEST_SKIP(); + } + + EXPECT_THAT(output, StartsWith("LAMMPS (")); + EXPECT_THAT(output, HasSubstr("Loop time")); + + // abort if running in parallel and not all atoms are local + const int nlocal = lmp->atom->nlocal; + ASSERT_EQ(lmp->atom->natoms, nlocal); + + // relax error a bit for KOKKOS package + double epsilon = 5.0 * test_config.epsilon; + + ErrorStats stats; + auto dihedral = lmp->force->dihedral; + + EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("init_stress (newton on)", dihedral->virial, test_config.init_stress, + 10 * epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(dihedral->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "init_energy stats, newton on: " << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + run_lammps(lmp); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_FORCES("run_forces (newton on)", lmp->atom, test_config.run_forces, 10 * epsilon); + EXPECT_STRESS("run_stress (newton on)", dihedral->virial, test_config.run_stress, 10 * epsilon); + + stats.reset(); + int id = lmp->modify->find_compute("sum"); + double energy = lmp->modify->compute[id]->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(dihedral->energy, test_config.run_energy, epsilon); + + // FIXME: this is currently broken ??? for KOKKOS with dihedral style hybrid + // needs to be fixed in the main code somewhere. Not sure where, though. + //if (test_config.dihedral_style.substr(0, 6) != "hybrid") + // EXPECT_FP_LE_WITH_EPS(dihedral->energy, energy, epsilon); + //if (print_stats) std::cerr << "run_energy stats, newton on: " << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + cleanup_lammps(lmp, test_config); + lmp = init_lammps(args, test_config, false); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + // skip over these tests if newton bond is forced to be on + if (lmp->force->newton_bond == 0) { + dihedral = lmp->force->dihedral; + + EXPECT_FORCES("init_forces (newton off)", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("init_stress (newton off)", dihedral->virial, test_config.init_stress, + 10 * epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(dihedral->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "init_energy stats, newton off:" << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + run_lammps(lmp); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_FORCES("run_forces (newton off)", lmp->atom, test_config.run_forces, 10 * epsilon); + EXPECT_STRESS("run_stress (newton off)", dihedral->virial, test_config.run_stress, + 10 * epsilon); + + stats.reset(); + id = lmp->modify->find_compute("sum"); + energy = lmp->modify->compute[id]->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(dihedral->energy, test_config.run_energy, epsilon); + + // FIXME: this is currently broken ??? for KOKKOS with dihedral style hybrid + // needs to be fixed in the main code somewhere. Not sure where, though. + //if (test_config.dihedral_style.substr(0, 6) != "hybrid") + // EXPECT_FP_LE_WITH_EPS(dihedral->energy, energy, epsilon); + + if (print_stats) std::cerr << "run_energy stats, newton off:" << stats << std::endl; + } + + if (!verbose) ::testing::internal::CaptureStdout(); + cleanup_lammps(lmp, test_config); + if (!verbose) ::testing::internal::GetCapturedStdout(); +}; + TEST(DihedralStyle, numdiff) { if (!LAMMPS::is_installed_pkg("EXTRA-FIX")) GTEST_SKIP(); diff --git a/unittest/force-styles/test_improper_style.cpp b/unittest/force-styles/test_improper_style.cpp index 59028fb1ff..a65bf438df 100644 --- a/unittest/force-styles/test_improper_style.cpp +++ b/unittest/force-styles/test_improper_style.cpp @@ -527,6 +527,108 @@ TEST(ImproperStyle, omp) if (!verbose) ::testing::internal::GetCapturedStdout(); }; +TEST(ImproperStyle, kokkos_omp) +{ + if (!LAMMPS::is_installed_pkg("KOKKOS")) GTEST_SKIP(); + if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); + + LAMMPS::argv args = {"ImproperStyle", "-log", "none", "-echo", "screen", "-nocite", + "-k", "on", "t", "4", "-sf", "kk"}; + + ::testing::internal::CaptureStdout(); + LAMMPS *lmp = init_lammps(args, test_config, true); + + std::string output = ::testing::internal::GetCapturedStdout(); + if (verbose) std::cout << output; + + if (!lmp) { + std::cerr << "One or more prerequisite styles with /kk suffix\n" + "are not available in this LAMMPS configuration:\n"; + for (auto &prerequisite : test_config.prerequisites) { + std::cerr << prerequisite.first << "_style " << prerequisite.second << "\n"; + } + GTEST_SKIP(); + } + + EXPECT_THAT(output, StartsWith("LAMMPS (")); + EXPECT_THAT(output, HasSubstr("Loop time")); + + // abort if running in parallel and not all atoms are local + const int nlocal = lmp->atom->nlocal; + ASSERT_EQ(lmp->atom->natoms, nlocal); + + // relax error a bit for KOKKOS package + double epsilon = 5.0 * test_config.epsilon; + + ErrorStats stats; + auto improper = lmp->force->improper; + + EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("init_stress (newton on)", improper->virial, test_config.init_stress, + 10 * epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(improper->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "init_energy stats, newton on: " << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + run_lammps(lmp); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_FORCES("run_forces (newton on)", lmp->atom, test_config.run_forces, 10 * epsilon); + EXPECT_STRESS("run_stress (newton on)", improper->virial, test_config.run_stress, 10 * epsilon); + + stats.reset(); + int id = lmp->modify->find_compute("sum"); + double energy = lmp->modify->compute[id]->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(improper->energy, test_config.run_energy, epsilon); + // FIXME: this is currently broken ??? for KOKKOS with improper style hybrid + // needs to be fixed in the main code somewhere. Not sure where, though. + //if (test_config.improper_style.substr(0, 6) != "hybrid") + // EXPECT_FP_LE_WITH_EPS(improper->energy, energy, epsilon); + if (print_stats) std::cerr << "run_energy stats, newton on: " << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + cleanup_lammps(lmp, test_config); + lmp = init_lammps(args, test_config, false); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + // skip over these tests if newton bond is forced to be on + if (lmp->force->newton_bond == 0) { + improper = lmp->force->improper; + + EXPECT_FORCES("init_forces (newton off)", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("init_stress (newton off)", improper->virial, test_config.init_stress, + 10 * epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(improper->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "init_energy stats, newton off:" << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + run_lammps(lmp); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_FORCES("run_forces (newton off)", lmp->atom, test_config.run_forces, 10 * epsilon); + EXPECT_STRESS("run_stress (newton off)", improper->virial, test_config.run_stress, + 10 * epsilon); + + stats.reset(); + id = lmp->modify->find_compute("sum"); + energy = lmp->modify->compute[id]->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(improper->energy, test_config.run_energy, epsilon); + // FIXME: this is currently broken ??? for KOKKOS with improper style hybrid + // needs to be fixed in the main code somewhere. Not sure where, though. + //if (test_config.improper_style.substr(0, 6) != "hybrid") + // EXPECT_FP_LE_WITH_EPS(improper->energy, energy, epsilon); + if (print_stats) std::cerr << "run_energy stats, newton off:" << stats << std::endl; + } + + if (!verbose) ::testing::internal::CaptureStdout(); + cleanup_lammps(lmp, test_config); + if (!verbose) ::testing::internal::GetCapturedStdout(); +}; + TEST(ImproperStyle, numdiff) { if (!LAMMPS::is_installed_pkg("EXTRA-FIX")) GTEST_SKIP();