diff --git a/unittest/force-styles/test_bond_style.cpp b/unittest/force-styles/test_bond_style.cpp index 185d28089e..c01d71f7d7 100644 --- a/unittest/force-styles/test_bond_style.cpp +++ b/unittest/force-styles/test_bond_style.cpp @@ -531,6 +531,111 @@ 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) { diff --git a/unittest/force-styles/test_dihedral_style.cpp b/unittest/force-styles/test_dihedral_style.cpp index efc37b9e03..b3d712417b 100644 --- a/unittest/force-styles/test_dihedral_style.cpp +++ b/unittest/force-styles/test_dihedral_style.cpp @@ -533,6 +533,111 @@ 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) { diff --git a/unittest/force-styles/test_fix_timestep.cpp b/unittest/force-styles/test_fix_timestep.cpp index 2d2c2fa0b8..c1fd32817d 100644 --- a/unittest/force-styles/test_fix_timestep.cpp +++ b/unittest/force-styles/test_fix_timestep.cpp @@ -839,3 +839,302 @@ TEST(FixTimestep, omp) cleanup_lammps(lmp, test_config); if (!verbose) ::testing::internal::GetCapturedStdout(); }; + +TEST(FixTimestep, 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 = {"FixTimestep", "-log", "none", "-echo", "screen", "-nocite", + "-k", "on", "t", "4", "-sf", "kk"}; + + ::testing::internal::CaptureStdout(); + LAMMPS *lmp = init_lammps(args, test_config); + 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; + // relax test precision when using pppm and single precision FFTs +#if defined(FFT_SINGLE) + if (lmp->force->kspace && utils::strmatch(lmp->force->kspace_style, "^pppm")) epsilon *= 2.0e8; +#endif + + ErrorStats stats; + + EXPECT_POSITIONS("run_pos (normal run, verlet)", lmp->atom, test_config.run_pos, epsilon); + EXPECT_VELOCITIES("run_vel (normal run, verlet)", lmp->atom, test_config.run_vel, epsilon); + + int ifix = lmp->modify->find_fix("test"); + if (ifix < 0) { + FAIL() << "ERROR: no fix defined with fix ID 'test'\n"; + } else { + Fix *fix = lmp->modify->fix[ifix]; + if (fix->thermo_virial) { + EXPECT_STRESS("run_stress (normal run, verlet)", fix->virial, test_config.run_stress, + epsilon); + } + + stats.reset(); + // global scalar + if (fix->scalar_flag) { + double value = fix->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(test_config.global_scalar, value, epsilon); + } + + // global vector + if (fix->vector_flag) { + int num = fix->size_vector; + EXPECT_EQ(num, test_config.global_vector.size()); + + for (int i = 0; i < num; ++i) + EXPECT_FP_LE_WITH_EPS(test_config.global_vector[i], fix->compute_vector(i), + epsilon); + } + + // check t_target for thermostats + + int dim = -1; + double *ptr = (double *)fix->extract("t_target", dim); + if ((ptr != nullptr) && (dim == 0)) { + int ivar = lmp->input->variable->find("t_target"); + if (ivar >= 0) { + double t_ref = atof(lmp->input->variable->retrieve("t_target")); + double t_target = *ptr; + EXPECT_FP_LE_WITH_EPS(t_target, t_ref, epsilon); + } + } + if (print_stats && stats.has_data()) + std::cerr << "global_data, normal run, verlet: " << stats << std::endl; + } + + if (!verbose) ::testing::internal::CaptureStdout(); + restart_lammps(lmp, test_config, false, false); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_POSITIONS("run_pos (restart, verlet)", lmp->atom, test_config.run_pos, epsilon); + EXPECT_VELOCITIES("run_vel (restart, verlet)", lmp->atom, test_config.run_vel, epsilon); + + ifix = lmp->modify->find_fix("test"); + if (ifix < 0) { + FAIL() << "ERROR: no fix defined with fix ID 'test'\n"; + } else { + Fix *fix = lmp->modify->fix[ifix]; + if (fix->thermo_virial) { + EXPECT_STRESS("run_stress (restart, verlet)", fix->virial, test_config.run_stress, + epsilon); + } + + stats.reset(); + + // global scalar + if (fix->scalar_flag) { + double value = fix->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(test_config.global_scalar, value, epsilon); + } + + // global vector + if (fix->vector_flag) { + int num = fix->size_vector; + EXPECT_EQ(num, test_config.global_vector.size()); + + for (int i = 0; i < num; ++i) + EXPECT_FP_LE_WITH_EPS(test_config.global_vector[i], fix->compute_vector(i), + epsilon); + } + if (print_stats && stats.has_data()) + std::cerr << "global_data, restart, verlet: " << stats << std::endl; + } + + if (lmp->atom->rmass == nullptr) { + if (!verbose) ::testing::internal::CaptureStdout(); + restart_lammps(lmp, test_config, true, false); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_POSITIONS("run_pos (rmass, verlet)", lmp->atom, test_config.run_pos, epsilon); + EXPECT_VELOCITIES("run_vel (rmass, verlet)", lmp->atom, test_config.run_vel, epsilon); + + ifix = lmp->modify->find_fix("test"); + if (ifix < 0) { + FAIL() << "ERROR: no fix defined with fix ID 'test'\n"; + } else { + Fix *fix = lmp->modify->fix[ifix]; + if (fix->thermo_virial) { + EXPECT_STRESS("run_stress (rmass, verlet)", fix->virial, test_config.run_stress, + epsilon); + } + + stats.reset(); + + // global scalar + if (fix->scalar_flag) { + double value = fix->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(test_config.global_scalar, value, epsilon); + } + + // global vector + if (fix->vector_flag) { + int num = fix->size_vector; + EXPECT_EQ(num, test_config.global_vector.size()); + + for (int i = 0; i < num; ++i) + EXPECT_FP_LE_WITH_EPS(test_config.global_vector[i], fix->compute_vector(i), + epsilon); + } + if (print_stats && stats.has_data()) + std::cerr << "global_data, rmass, verlet: " << stats << std::endl; + } + } + + // rigid fixes need work to test properly with r-RESPA, + // also, torque is not supported by respa/omp + ifix = lmp->modify->find_fix("test"); + if (!utils::strmatch(lmp->modify->fix[ifix]->style, "^rigid") && !lmp->atom->torque) { + + if (!verbose) ::testing::internal::CaptureStdout(); + cleanup_lammps(lmp, test_config); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + ::testing::internal::CaptureStdout(); + lmp = init_lammps(args, test_config, true); + output = ::testing::internal::GetCapturedStdout(); + if (verbose) std::cout << output; + + // lower required precision by two orders of magnitude to accommodate respa + epsilon *= 100.0; + + EXPECT_POSITIONS("run_pos (normal run, respa)", lmp->atom, test_config.run_pos, epsilon); + EXPECT_VELOCITIES("run_vel (normal run, respa)", lmp->atom, test_config.run_vel, epsilon); + + ifix = lmp->modify->find_fix("test"); + if (ifix < 0) { + FAIL() << "ERROR: no fix defined with fix ID 'test'\n"; + } else { + Fix *fix = lmp->modify->fix[ifix]; + if (fix->thermo_virial) { + EXPECT_STRESS("run_stress (normal run, respa)", fix->virial, test_config.run_stress, + 1000 * epsilon); + } + + stats.reset(); + + // global scalar + if (fix->scalar_flag) { + double value = fix->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(test_config.global_scalar, value, 10 * epsilon); + } + + // global vector + if (fix->vector_flag) { + int num = fix->size_vector; + EXPECT_EQ(num, test_config.global_vector.size()); + + for (int i = 0; i < num; ++i) + EXPECT_FP_LE_WITH_EPS(test_config.global_vector[i], fix->compute_vector(i), + 10 * epsilon); + } + if (print_stats && stats.has_data()) + std::cerr << "global_data, normal run, respa: " << stats << std::endl; + } + + if (!verbose) ::testing::internal::CaptureStdout(); + restart_lammps(lmp, test_config, false, true); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_POSITIONS("run_pos (restart, respa)", lmp->atom, test_config.run_pos, epsilon); + EXPECT_VELOCITIES("run_vel (restart, respa)", lmp->atom, test_config.run_vel, epsilon); + + ifix = lmp->modify->find_fix("test"); + if (ifix < 0) { + FAIL() << "ERROR: no fix defined with fix ID 'test'\n"; + } else { + Fix *fix = lmp->modify->fix[ifix]; + if (fix->thermo_virial) { + EXPECT_STRESS("run_stress (restart, respa)", fix->virial, test_config.run_stress, + 1000 * epsilon); + } + + stats.reset(); + + // global scalar + if (fix->scalar_flag) { + double value = fix->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(test_config.global_scalar, value, 10 * epsilon); + } + + // global vector + if (fix->vector_flag) { + int num = fix->size_vector; + EXPECT_EQ(num, test_config.global_vector.size()); + + for (int i = 0; i < num; ++i) + EXPECT_FP_LE_WITH_EPS(test_config.global_vector[i], fix->compute_vector(i), + 10 * epsilon); + } + if (print_stats && stats.has_data()) + std::cerr << "global_data, restart, respa: " << stats << std::endl; + } + + if (lmp->atom->rmass == nullptr) { + if (!verbose) ::testing::internal::CaptureStdout(); + restart_lammps(lmp, test_config, true, true); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_POSITIONS("run_pos (rmass, respa)", lmp->atom, test_config.run_pos, epsilon); + EXPECT_VELOCITIES("run_vel (rmass, respa)", lmp->atom, test_config.run_vel, epsilon); + + ifix = lmp->modify->find_fix("test"); + if (ifix < 0) { + FAIL() << "ERROR: no fix defined with fix ID 'test'\n"; + } else { + Fix *fix = lmp->modify->fix[ifix]; + if (fix->thermo_virial) { + EXPECT_STRESS("run_stress (rmass, respa)", fix->virial, test_config.run_stress, + 1000 * epsilon); + } + + stats.reset(); + + // global scalar + if (fix->scalar_flag) { + double value = fix->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(test_config.global_scalar, value, 10 * epsilon); + } + + // global vector + if (fix->vector_flag) { + int num = fix->size_vector; + EXPECT_EQ(num, test_config.global_vector.size()); + + for (int i = 0; i < num; ++i) + EXPECT_FP_LE_WITH_EPS(test_config.global_vector[i], fix->compute_vector(i), + 10 * epsilon); + } + if (print_stats && stats.has_data()) + std::cerr << "global_data, rmass, respa: " << stats << std::endl; + } + } + } + + if (!verbose) ::testing::internal::CaptureStdout(); + cleanup_lammps(lmp, test_config); + if (!verbose) ::testing::internal::GetCapturedStdout(); +}; + diff --git a/unittest/force-styles/test_improper_style.cpp b/unittest/force-styles/test_improper_style.cpp index ba3618d3dc..5c82efffe2 100644 --- a/unittest/force-styles/test_improper_style.cpp +++ b/unittest/force-styles/test_improper_style.cpp @@ -526,6 +526,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", + "-pk", "omp", "4", "-sf", "omp"}; + + ::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();