From 6c0399c6addecfd32800b81627d30736a817a4ef Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Wed, 14 Oct 2026 21:22:27 +0800 Subject: [PATCH 01/33] WIP: add CPU SNAP potential support --- source/source_esolver/CMakeLists.txt | 1 + source/source_esolver/esolver_factory.cpp | 9 + source/source_esolver/esolver_snap.cpp | 268 +++++++++ source/source_esolver/esolver_snap.h | 40 ++ .../module_parameter/input_parameter.h | 2 +- .../source_io/module_parameter/md_parameter.h | 1 + .../module_parameter/read_inp_sys.cpp | 9 +- .../module_parameter/read_input_item_md.cpp | 12 + source/source_main/driver_run.cpp | 3 +- source/source_md/CMakeLists.txt | 2 + source/source_md/snap/CMakeLists.txt | 12 + source/source_md/snap/snap_calculator.cpp | 164 ++++++ source/source_md/snap/snap_calculator.h | 55 ++ source/source_md/snap/snap_clebsch_gordan.cpp | 168 ++++++ source/source_md/snap/snap_clebsch_gordan.h | 58 ++ source/source_md/snap/snap_descriptor.cpp | 510 ++++++++++++++++++ source/source_md/snap/snap_descriptor.h | 79 +++ source/source_md/snap/snap_model.cpp | 285 ++++++++++ source/source_md/snap/snap_model.h | 49 ++ source/source_md/snap/test/CMakeLists.txt | 21 + .../snap/test/test_snap_calculator.cpp | 85 +++ .../snap/test/test_snap_clebsch_gordan.cpp | 32 ++ .../snap/test/test_snap_descriptor.cpp | 103 ++++ .../source_md/snap/test/test_snap_model.cpp | 93 ++++ 24 files changed, 2057 insertions(+), 4 deletions(-) create mode 100644 source/source_esolver/esolver_snap.cpp create mode 100644 source/source_esolver/esolver_snap.h create mode 100644 source/source_md/snap/CMakeLists.txt create mode 100644 source/source_md/snap/snap_calculator.cpp create mode 100644 source/source_md/snap/snap_calculator.h create mode 100644 source/source_md/snap/snap_clebsch_gordan.cpp create mode 100644 source/source_md/snap/snap_clebsch_gordan.h create mode 100644 source/source_md/snap/snap_descriptor.cpp create mode 100644 source/source_md/snap/snap_descriptor.h create mode 100644 source/source_md/snap/snap_model.cpp create mode 100644 source/source_md/snap/snap_model.h create mode 100644 source/source_md/snap/test/CMakeLists.txt create mode 100644 source/source_md/snap/test/test_snap_calculator.cpp create mode 100644 source/source_md/snap/test/test_snap_clebsch_gordan.cpp create mode 100644 source/source_md/snap/test/test_snap_descriptor.cpp create mode 100644 source/source_md/snap/test/test_snap_model.cpp diff --git a/source/source_esolver/CMakeLists.txt b/source/source_esolver/CMakeLists.txt index 95488f4be33..6caba672b8f 100644 --- a/source/source_esolver/CMakeLists.txt +++ b/source/source_esolver/CMakeLists.txt @@ -9,6 +9,7 @@ list(APPEND objects esolver_lj.cpp esolver_dp.cpp esolver_nep.cpp + esolver_snap.cpp esolver_of.cpp esolver_of_tddft.cpp esolver_of_interface.cpp diff --git a/source/source_esolver/esolver_factory.cpp b/source/source_esolver/esolver_factory.cpp index 51c8bb91dd9..c1e7da7d0f3 100644 --- a/source/source_esolver/esolver_factory.cpp +++ b/source/source_esolver/esolver_factory.cpp @@ -23,6 +23,7 @@ #endif #include "esolver_dp.h" #include "esolver_nep.h" +#include "esolver_snap.h" #include "esolver_lj.h" #include "esolver_of.h" #include "esolver_of_tddft.h" @@ -113,6 +114,10 @@ std::string determine_type(const Input_para& inp) { esolver_type = "nep_pot"; } + else if (inp.esolver_type == "snap") + { + esolver_type = "snap_pot"; + } else if (esolver_type == "none") { ModuleBase::WARNING_QUIT("ESolver", "No such esolver_type combined with basis_type"); @@ -387,6 +392,10 @@ ESolver* init_esolver(const Input_para& inp) { return new ESolver_NEP(PARAM.mdp.pot_file); } + else if (esolver_type == "snap_pot") + { + return new ESolver_SNAP(PARAM.mdp.pot_file, PARAM.mdp.snap_param_file); + } throw std::invalid_argument("esolver_type = " + std::string(esolver_type) + ". Wrong in " + std::string(__FILE__) + " line " + std::to_string(__LINE__)); } diff --git a/source/source_esolver/esolver_snap.cpp b/source/source_esolver/esolver_snap.cpp new file mode 100644 index 00000000000..c77916756b2 --- /dev/null +++ b/source/source_esolver/esolver_snap.cpp @@ -0,0 +1,268 @@ +#include "esolver_snap.h" + +#include "source_base/constants.h" +#include "source_base/global_variable.h" +#include "source_base/parallel_reduce.h" +#include "source_cell/mdcell.h" +#include "source_cell/module_neighlist/neighbor_search.h" +#include "source_io/module_output/output_log.h" +#include "source_io/module_parameter/parameter.h" + +#include +#include +#include + +namespace ModuleESolver +{ + +namespace +{ +void fail(const std::string& message) +{ + ModuleBase::WARNING_QUIT("ESolver_SNAP", message); +} + +ModuleMD::SNAP::Neighbor make_neighbor(const NeighborAtom& center, + const NeighborAtom& neighbor, + const double lat0, + const ModuleMD::SNAP::ModelParameters& parameters) +{ + ModuleMD::SNAP::Neighbor result; + result.x = (neighbor.position_x - center.position_x) * lat0 * ModuleBase::BOHR_TO_A; + result.y = (neighbor.position_y - center.position_y) * lat0 * ModuleBase::BOHR_TO_A; + result.z = (neighbor.position_z - center.position_z) * lat0 * ModuleBase::BOHR_TO_A; + result.weight = parameters.element_weights[static_cast(neighbor.atom_type)]; + result.cutoff_radius = (parameters.element_radii[static_cast(center.atom_type)] + + parameters.element_radii[static_cast(neighbor.atom_type)]) + * parameters.rcutfac; + return result; +} +} + +ESolver_SNAP::ESolver_SNAP(const std::string& coefficient_file, const std::string& parameter_file) + : coefficient_file_(coefficient_file), parameter_file_(parameter_file) +{ + classname = "ESolver_SNAP"; +} + +void ESolver_SNAP::initialize(const std::vector& labels) +{ + std::string error; + if (!model_.load(coefficient_file_, parameter_file_, labels, error)) + { + fail(error); + } + calculator_.reset(new ModuleMD::SNAP::Calculator(model_)); + snap_virial_.create(3, 3); +} + +void ESolver_SNAP::before_all_runners(BaseCell& cell, const Input_para& inp) +{ + inp_ = &inp; + if (cell.kind() == BaseCell::Kind::mdcell) + { + MDCell& mdcell = static_cast(cell); + initialize(mdcell.type_labels()); + mdcell.set_neighbor_cutoff(model_.parameters.rcut * ModuleBase::ANGSTROM_AU); + return; + } + + UnitCell& ucell = static_cast(cell); + std::vector labels; + for (int it = 0; it < ucell.ntype; ++it) + { + labels.push_back(ucell.atoms[it].label); + } + initialize(labels); + snap_force_.create(ucell.nat, 3); +} + +void ESolver_SNAP::runner(BaseCell& cell, const int istep) +{ + static_cast(istep); + if (!calculator_) + { + fail("SNAP solver was not initialized."); + } + snap_potential_ = 0.0; + snap_virial_.zero_out(); + + if (cell.kind() == BaseCell::Kind::mdcell) + { + MDCell& mdcell = static_cast(cell); + if (!mdcell.has_neighbor_search()) + { + fail("MDCell neighbors must be prepared before ESolver_SNAP::runner()."); + } + std::vector& owned_atoms = mdcell.owned_atoms(); + const std::vector& all_atoms = mdcell.neighbor_search().get_all_atoms(); + const NeighborList& list = mdcell.neighbor_search().get_neighbor_list(); + const int nowned = static_cast(owned_atoms.size()); + std::vector > all_force(all_atoms.size()); + for (int i = 0; i < nowned; ++i) + { + const NeighborAtom center(owned_atoms[static_cast(i)].cart.x, + owned_atoms[static_cast(i)].cart.y, + owned_atoms[static_cast(i)].cart.z, + owned_atoms[static_cast(i)].type, + i, + i); + std::vector neighbors; + for (int k = 0; k < list.get_numneigh(i); ++k) + { + const int neighbor_index = list.get_firstneigh(i)[k]; + const NeighborAtom& neighbor = all_atoms[static_cast(neighbor_index)]; + if (neighbor.atom_type < 0 || static_cast(neighbor.atom_type) >= model_.parameters.elements.size()) + { + fail("MDCell atom type is outside the SNAP element map."); + } + neighbors.push_back(make_neighbor(center, neighbor, mdcell.lat0(), model_.parameters)); + } + const ModuleMD::SNAP::ForceResult result = calculator_->compute_with_analytic_force( + neighbors, static_cast(center.atom_type)); + snap_potential_ += result.energy.energy / ModuleBase::Ry_to_eV; + all_force[static_cast(i)] += ModuleBase::Vector3(result.center_force[0], + result.center_force[1], + result.center_force[2]); + for (std::size_t k = 0; k < result.neighbor_forces.size(); ++k) + { + const int neighbor_index = list.get_firstneigh(i)[static_cast(k)]; + all_force[static_cast(neighbor_index)] += + ModuleBase::Vector3(result.neighbor_forces[k][0], + result.neighbor_forces[k][1], + result.neighbor_forces[k][2]); + const NeighborAtom& neighbor = all_atoms[static_cast(neighbor_index)]; + const double relative[3] = { + (center.position_x - neighbor.position_x) * mdcell.lat0() * ModuleBase::BOHR_TO_A, + (center.position_y - neighbor.position_y) * mdcell.lat0() * ModuleBase::BOHR_TO_A, + (center.position_z - neighbor.position_z) * mdcell.lat0() * ModuleBase::BOHR_TO_A}; + const double pair_force[3] = {-result.neighbor_forces[k][0], + -result.neighbor_forces[k][1], + -result.neighbor_forces[k][2]}; + for (int row = 0; row < 3; ++row) + { + for (int column = 0; column < 3; ++column) + { + snap_virial_(row, column) += relative[row] * pair_force[column] + / (ModuleBase::Ry_to_eV * mdcell.omega()); + } + } + } + } + for (std::size_t i = 0; i < mdcell.ghost_atoms().size(); ++i) + { + mdcell.ghost_atoms()[i].force = all_force[nowned + i]; + } + Parallel_Reduce::reduce_all(snap_potential_); + Parallel_Reduce::reduce_all(snap_virial_.c, 9); + for (int i = 0; i < nowned; ++i) + { + owned_atoms[static_cast(i)].force.set( + all_force[static_cast(i)].x / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU), + all_force[static_cast(i)].y / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU), + all_force[static_cast(i)].z / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU)); + } + return; + } + + UnitCell& ucell = static_cast(cell); + NeighborSearch search; + search.init(ucell, model_.parameters.rcut * ModuleBase::ANGSTROM_AU); + search.build_neighbors(); + const NeighborList& list = search.get_neighbor_list(); + const std::vector& inside = search.get_inside_atoms(); + const std::vector& all = search.get_all_atoms(); + snap_force_.zero_out(); + std::vector offsets(static_cast(ucell.ntype + 1), 0); + for (int it = 0; it < ucell.ntype; ++it) + { + offsets[static_cast(it + 1)] = offsets[static_cast(it)] + ucell.atoms[it].na; + } + for (int local_i = 0; local_i < list.get_ncentral_atoms(); ++local_i) + { + const NeighborAtom& center = inside[static_cast(local_i)]; + std::vector neighbors; + std::vector atom_indices; + for (int k = 0; k < list.get_numneigh(local_i); ++k) + { + const NeighborAtom& neighbor = all[static_cast(list.get_firstneigh(local_i)[k])]; + neighbors.push_back(make_neighbor(center, neighbor, ucell.lat0, model_.parameters)); + atom_indices.push_back(offsets[static_cast(neighbor.atom_type)] + neighbor.atom_index); + } + const std::size_t center_element = static_cast(center.atom_type); + const ModuleMD::SNAP::ForceResult result = calculator_->compute_with_analytic_force(neighbors, center_element); + snap_potential_ += result.energy.energy / ModuleBase::Ry_to_eV; + for (std::size_t k = 0; k < atom_indices.size(); ++k) + { + const NeighborAtom& neighbor = all[static_cast(list.get_firstneigh(local_i)[static_cast(k)])]; + const double dx = (center.position_x - neighbor.position_x) * ucell.lat0 * ModuleBase::BOHR_TO_A; + const double dy = (center.position_y - neighbor.position_y) * ucell.lat0 * ModuleBase::BOHR_TO_A; + const double dz = (center.position_z - neighbor.position_z) * ucell.lat0 * ModuleBase::BOHR_TO_A; + const double center_force_x = -result.neighbor_forces[k][0]; + const double center_force_y = -result.neighbor_forces[k][1]; + const double center_force_z = -result.neighbor_forces[k][2]; + const double relative[3] = {dx, dy, dz}; + const double pair_force[3] = {center_force_x, center_force_y, center_force_z}; + for (int row = 0; row < 3; ++row) + { + for (int column = 0; column < 3; ++column) + { + snap_virial_(row, column) += relative[row] * pair_force[column] + / (ModuleBase::Ry_to_eV * ucell.omega); + } + } + } + const int center_index = offsets[static_cast(center.atom_type)] + center.atom_index; + for (int direction = 0; direction < 3; ++direction) + { + snap_force_(center_index, direction) += + result.center_force[static_cast(direction)] + / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU); + } + for (std::size_t k = 0; k < atom_indices.size(); ++k) + { + for (int direction = 0; direction < 3; ++direction) + { + snap_force_(atom_indices[k], direction) += + result.neighbor_forces[k][static_cast(direction)] + / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU); + } + } + } +} + +double ESolver_SNAP::cal_energy() +{ + return snap_potential_; +} + +void ESolver_SNAP::cal_force(BaseCell& cell, ModuleBase::matrix& force) +{ + if (cell.kind() == BaseCell::Kind::mdcell) + { + const MDCell& mdcell = static_cast(cell); + force.create(mdcell.owned_atoms().size(), 3); + for (std::size_t i = 0; i < mdcell.owned_atoms().size(); ++i) + { + force(i, 0) = mdcell.owned_atoms()[i].force.x; + force(i, 1) = mdcell.owned_atoms()[i].force.y; + force(i, 2) = mdcell.owned_atoms()[i].force.z; + } + return; + } + force = snap_force_; +} + +void ESolver_SNAP::cal_stress(BaseCell& cell, ModuleBase::matrix& stress) +{ + static_cast(cell); + stress = snap_virial_; +} + +void ESolver_SNAP::after_all_runners(BaseCell& cell) +{ + static_cast(cell); + GlobalV::ofs_running << "\n !FINAL_ETOT_IS " << snap_potential_ * ModuleBase::Ry_to_eV << " eV\n"; +} + +} // namespace ModuleESolver diff --git a/source/source_esolver/esolver_snap.h b/source/source_esolver/esolver_snap.h new file mode 100644 index 00000000000..c4c7aba2cdf --- /dev/null +++ b/source/source_esolver/esolver_snap.h @@ -0,0 +1,40 @@ +#ifndef ESOLVER_SNAP_H +#define ESOLVER_SNAP_H + +#include "esolver.h" +#include "source_md/snap/snap_calculator.h" + +#include +#include +#include + +namespace ModuleESolver +{ + +class ESolver_SNAP : public ESolver +{ + public: + ESolver_SNAP(const std::string& coefficient_file, const std::string& parameter_file); + + void before_all_runners(BaseCell& cell, const Input_para& inp) override; + void runner(BaseCell& cell, int istep) override; + double cal_energy() override; + void cal_force(BaseCell& cell, ModuleBase::matrix& force) override; + void cal_stress(BaseCell& cell, ModuleBase::matrix& stress) override; + void after_all_runners(BaseCell& cell) override; + + private: + void initialize(const std::vector& labels); + + std::string coefficient_file_; + std::string parameter_file_; + ModuleMD::SNAP::ModelData model_; + std::unique_ptr calculator_; + double snap_potential_ = 0.0; + ModuleBase::matrix snap_force_; + ModuleBase::matrix snap_virial_; +}; + +} // namespace ModuleESolver + +#endif // ESOLVER_SNAP_H diff --git a/source/source_io/module_parameter/input_parameter.h b/source/source_io/module_parameter/input_parameter.h index 8f07b087a3f..10d62e91669 100644 --- a/source/source_io/module_parameter/input_parameter.h +++ b/source/source_io/module_parameter/input_parameter.h @@ -21,7 +21,7 @@ struct Input_para ///< "nscf" : non-self consistent calculation. ///< "relax" : cell relaxations bool socket_driver = false; ///< run ABACUS as an i-PI socket client - std::string esolver_type = "ksdft"; ///< the energy solver: ksdft, sdft, ofdft, tddft, lj, dp + std::string esolver_type = "ksdft"; ///< the energy solver: ksdft, sdft, ofdft, tddft, lj, dp, nep, snap /* symmetry level: -1, no symmetry at all; 0, only basic time reversal would be considered; diff --git a/source/source_io/module_parameter/md_parameter.h b/source/source_io/module_parameter/md_parameter.h index 706218e6960..53fc63f2411 100644 --- a/source/source_io/module_parameter/md_parameter.h +++ b/source/source_io/module_parameter/md_parameter.h @@ -31,6 +31,7 @@ struct MD_para std::vector lj_epsilon = {}; ///< the value of epsilon for LJ potential (eV) std::vector lj_sigma = {}; ///< the value of sigma for LJ potential (\AA) std::string pot_file = "graph.pb"; ///< the filename of potential files for CMD such as DP + std::string snap_param_file = "snapparam"; ///< SNAP parameter file double dp_rescaling = 1.0; ///< rescaling factor for DP model. Energy, force and stress will be multiplied by this factor. std::vector dp_fparam = {}; ///< The frame parameter for dp potential. The array can be of size : diff --git a/source/source_io/module_parameter/read_inp_sys.cpp b/source/source_io/module_parameter/read_inp_sys.cpp index a0ba7ff398a..bd8294dbfcd 100644 --- a/source/source_io/module_parameter/read_inp_sys.cpp +++ b/source/source_io/module_parameter/read_inp_sys.cpp @@ -244,24 +244,29 @@ Socket mode always computes energy. Force and stress extraction follows cal_forc * lj: Leonard Jones potential * dp: DeeP potential * nep: Neuroevolution Potential +* snap: Spectral Neighbor Analysis Potential * ks-lr: Kohn-Sham density functional theory + LR-TDDFT (Under Development Feature) * lr: LR-TDDFT with given KS orbitals (Under Development Feature) * dfpt: density functional perturbation theory (Under Development Feature))"; item.default_value = "ksdft"; read_sync_string(input.esolver_type); item.check_value = [](const Input_Item& item, const Parameter& para) { - const std::vector esolver_types = { "ksdft", "sdft", "ofdft", "tdofdft", "tddft", "lj", "dp", "nep", "lr", "ks-lr", "dfpt" }; + const std::vector esolver_types = { "ksdft", "sdft", "ofdft", "tdofdft", "tddft", "lj", "dp", "nep", "snap", "lr", "ks-lr", "dfpt" }; if (std::find(esolver_types.begin(), esolver_types.end(), para.input.esolver_type) == esolver_types.end()) { const std::string warningstr = nofound_str(esolver_types, "esolver_type"); ModuleBase::WARNING_QUIT("ReadInput", warningstr); } - if (para.input.esolver_type == "dp" || para.input.esolver_type == "nep") + if (para.input.esolver_type == "dp" || para.input.esolver_type == "nep" || para.input.esolver_type == "snap") { if (access(para.input.mdp.pot_file.c_str(), 0) == -1) { ModuleBase::WARNING_QUIT("ReadInput", "Can not find `pot_file` !"); } + if (para.input.esolver_type == "snap" && access(para.input.mdp.snap_param_file.c_str(), 0) == -1) + { + ModuleBase::WARNING_QUIT("ReadInput", "Can not find `snap_param_file` !"); + } } // LR reads the ground state wave function from a separate SCF run, // so it cannot be combined with a self-consistent calculation. diff --git a/source/source_io/module_parameter/read_input_item_md.cpp b/source/source_io/module_parameter/read_input_item_md.cpp index d5f6dc6bd67..f2ad2d62f14 100644 --- a/source/source_io/module_parameter/read_input_item_md.cpp +++ b/source/source_io/module_parameter/read_input_item_md.cpp @@ -549,6 +549,18 @@ Note: It is a system-dependent empirical parameter. An improper choice might lea read_sync_string(input.mdp.pot_file); this->add_item(item); } + { + Input_Item item("snap_param_file"); + item.annotation = "the SNAP parameter file"; + item.category = "Molecular dynamics"; + item.type = "String"; + item.description = "The SNAP parameter file used with pot_file as the SNAP coefficient file."; + item.default_value = "snapparam"; + item.unit = ""; + item.set_availability("esolver_type==snap"); + read_sync_string(input.mdp.snap_param_file); + this->add_item(item); + } { Input_Item item("dp_rescaling"); item.annotation = "rescaling factor for dp potential"; diff --git a/source/source_main/driver_run.cpp b/source/source_main/driver_run.cpp index bb637ce69a2..e0a8ea289aa 100644 --- a/source/source_main/driver_run.cpp +++ b/source/source_main/driver_run.cpp @@ -52,7 +52,8 @@ void Driver::driver_run() this->init_hardware(); ModuleESolver::ESolver* p_esolver = ModuleESolver::init_esolver(PARAM.inp); - const bool direct_mdcell = input.esolver_type == "lj" || input.esolver_type == "dp" || input.esolver_type == "nep"; + const bool direct_mdcell = input.esolver_type == "lj" || input.esolver_type == "dp" || input.esolver_type == "nep" + || input.esolver_type == "snap"; UnitCell ucell; bool ucell_initialized = false; const auto initialize_ucell = [&ucell, &ucell_initialized, &input]() diff --git a/source/source_md/CMakeLists.txt b/source/source_md/CMakeLists.txt index 000417d0d78..e8a9a9ac9f8 100644 --- a/source/source_md/CMakeLists.txt +++ b/source/source_md/CMakeLists.txt @@ -11,6 +11,8 @@ add_library( verlet.cpp ) +add_subdirectory(snap) + if(ENABLE_COVERAGE) add_coverage(md) endif() diff --git a/source/source_md/snap/CMakeLists.txt b/source/source_md/snap/CMakeLists.txt new file mode 100644 index 00000000000..2ac1c97479e --- /dev/null +++ b/source/source_md/snap/CMakeLists.txt @@ -0,0 +1,12 @@ +target_sources( + md + PRIVATE + snap_calculator.cpp + snap_descriptor.cpp + snap_model.cpp + snap_clebsch_gordan.cpp +) + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/source/source_md/snap/snap_calculator.cpp b/source/source_md/snap/snap_calculator.cpp new file mode 100644 index 00000000000..e2fb8843627 --- /dev/null +++ b/source/source_md/snap/snap_calculator.cpp @@ -0,0 +1,164 @@ +#include "snap_calculator.h" + +#include + +namespace ModuleMD +{ +namespace SNAP +{ + +Calculator::Calculator(const ModelData& model) + : model_(model), descriptor_evaluator_(model.parameters), descriptor_size_(descriptor_evaluator_.bispectrum_size()) +{ + if (model_.coefficients.size() != model_.parameters.elements.size()) + { + throw std::invalid_argument("SNAP coefficient blocks do not match the element list."); + } + const std::size_t expected_count = descriptor_size_ + 1 + + (model_.parameters.quadratic_flag + ? descriptor_size_ * (descriptor_size_ + 1) / 2 + : 0); + for (std::size_t element = 0; element < model_.coefficients.size(); ++element) + { + if (model_.coefficients[element].size() != expected_count) + { + throw std::invalid_argument("SNAP coefficient count does not match the descriptor size."); + } + } +} + +EnergyResult Calculator::compute(const std::vector& neighbors, const std::size_t central_element) const +{ + if (central_element >= model_.coefficients.size()) + { + throw std::out_of_range("SNAP central element index is outside the model."); + } + + EnergyResult result; + result.descriptor = descriptor_evaluator_.compute_bispectrum(descriptor_evaluator_.accumulate_u(neighbors)); + if (model_.parameters.bzero_flag) + { + const std::vector bzero = + descriptor_evaluator_.compute_bispectrum(descriptor_evaluator_.accumulate_u(std::vector())); + for (std::size_t index = 0; index < result.descriptor.size(); ++index) + { + result.descriptor[index] -= bzero[index]; + } + } + const std::vector& coefficients = model_.coefficients[central_element]; + result.energy = coefficients[0]; + for (std::size_t index = 0; index < result.descriptor.size(); ++index) + { + result.energy += coefficients[index + 1] * result.descriptor[index]; + } + if (model_.parameters.quadratic_flag) + { + std::size_t coefficient = result.descriptor.size() + 1; + for (std::size_t i = 0; i < result.descriptor.size(); ++i) + { + for (std::size_t j = i; j < result.descriptor.size(); ++j) + { + result.energy += coefficients[coefficient++] * result.descriptor[i] * result.descriptor[j] + * (i == j ? 0.5 : 1.0); + } + } + } + return result; +} + +ForceResult Calculator::compute_with_analytic_force(const std::vector& neighbors, + const std::size_t central_element) const +{ + if (central_element >= model_.coefficients.size()) + { + throw std::out_of_range("SNAP central element index is outside the model."); + } + ForceResult result; + result.energy = compute(neighbors, central_element); + result.center_force.assign(3, 0.0); + result.neighbor_forces.assign(neighbors.size(), std::vector(3, 0.0)); + const std::vector& coefficients = model_.coefficients[central_element]; + for (std::size_t neighbor_index = 0; neighbor_index < neighbors.size(); ++neighbor_index) + { + for (int direction = 0; direction < 3; ++direction) + { + const UWithDerivative u_derivative = + descriptor_evaluator_.compute_u_with_derivative(neighbors[neighbor_index], direction); + std::vector > u = descriptor_evaluator_.accumulate_u(neighbors); + std::vector > du(u.size(), std::complex(0.0, 0.0)); + for (std::size_t index = 0; index < du.size(); ++index) + { + du[index] = u_derivative.derivatives[index]; + } + const std::vector db = descriptor_evaluator_.compute_bispectrum_derivative(u, du); + double derivative = 0.0; + for (std::size_t index = 0; index < db.size(); ++index) + { + derivative += coefficients[index + 1] * db[index]; + } + if (model_.parameters.quadratic_flag) + { + std::size_t coefficient = db.size() + 1; + for (std::size_t i = 0; i < db.size(); ++i) + { + for (std::size_t j = i; j < db.size(); ++j) + { + const double factor = i == j ? 0.5 : 1.0; + derivative += coefficients[coefficient++] * factor + * (db[i] * result.energy.descriptor[j] + + result.energy.descriptor[i] * db[j]); + } + } + } + result.center_force[static_cast(direction)] += derivative; + result.neighbor_forces[neighbor_index][static_cast(direction)] = -derivative; + } + } + return result; +} + +ForceResult Calculator::compute_with_finite_difference_force(const std::vector& neighbors, + const std::size_t central_element, + const double displacement) const +{ + if (displacement <= 0.0) + { + throw std::invalid_argument("SNAP finite-difference displacement must be positive."); + } + ForceResult result; + result.energy = compute(neighbors, central_element); + result.center_force.assign(3, 0.0); + result.neighbor_forces.assign(neighbors.size(), std::vector(3, 0.0)); + + for (std::size_t neighbor_index = 0; neighbor_index < neighbors.size(); ++neighbor_index) + { + for (int direction = 0; direction < 3; ++direction) + { + std::vector plus = neighbors; + std::vector minus = neighbors; + if (direction == 0) + { + plus[neighbor_index].x += displacement; + minus[neighbor_index].x -= displacement; + } + else if (direction == 1) + { + plus[neighbor_index].y += displacement; + minus[neighbor_index].y -= displacement; + } + else + { + plus[neighbor_index].z += displacement; + minus[neighbor_index].z -= displacement; + } + const double derivative = + (compute(plus, central_element).energy - compute(minus, central_element).energy) / (2.0 * displacement); + result.center_force[static_cast(direction)] += derivative; + result.neighbor_forces[neighbor_index][static_cast(direction)] -= derivative; + } + } + return result; +} + +} // namespace SNAP +} // namespace ModuleMD diff --git a/source/source_md/snap/snap_calculator.h b/source/source_md/snap/snap_calculator.h new file mode 100644 index 00000000000..2eeed6b2a33 --- /dev/null +++ b/source/source_md/snap/snap_calculator.h @@ -0,0 +1,55 @@ +#ifndef SNAP_CALCULATOR_H +#define SNAP_CALCULATOR_H + +#include "snap_descriptor.h" +#include "snap_model.h" + +#include + +namespace ModuleMD +{ +namespace SNAP +{ + +struct EnergyResult +{ + double energy = 0.0; + std::vector descriptor; +}; + +struct ForceResult +{ + EnergyResult energy; + std::vector center_force; + std::vector > neighbor_forces; +}; + +class Calculator +{ + public: + explicit Calculator(const ModelData& model); + + EnergyResult compute(const std::vector& neighbors, std::size_t central_element) const; + + ForceResult compute_with_analytic_force(const std::vector& neighbors, + std::size_t central_element) const; + + ForceResult compute_with_finite_difference_force(const std::vector& neighbors, + std::size_t central_element, + double displacement) const; + + std::size_t descriptor_size() const + { + return descriptor_size_; + } + + private: + ModelData model_; + DescriptorEvaluator descriptor_evaluator_; + std::size_t descriptor_size_; +}; + +} // namespace SNAP +} // namespace ModuleMD + +#endif // SNAP_CALCULATOR_H diff --git a/source/source_md/snap/snap_clebsch_gordan.cpp b/source/source_md/snap/snap_clebsch_gordan.cpp new file mode 100644 index 00000000000..35670761ada --- /dev/null +++ b/source/source_md/snap/snap_clebsch_gordan.cpp @@ -0,0 +1,168 @@ +#include "snap_clebsch_gordan.h" + +#include + +namespace ModuleMD +{ +namespace SNAP +{ + +namespace +{ +int half_sum(const int left, const int right) +{ + return (left + right) / 2; +} +} + +ClebschGordanTable::ClebschGordanTable(const int twojmax) : twojmax_(twojmax < 0 ? 0 : twojmax) +{ + for (int j1 = 0; j1 <= twojmax_; ++j1) + { + for (int j2 = 0; j2 <= twojmax_; ++j2) + { + for (int j = std::abs(j1 - j2); j <= std::min(twojmax_, j1 + j2); j += 2) + { + for (int m1 = -j1; m1 <= j1; m1 += 2) + { + for (int m2 = -j2; m2 <= j2; m2 += 2) + { + const int m = m1 + m2; + if (m < -j || m > j) + { + continue; + } + Entry entry; + entry.j1 = j1; + entry.m1 = m1; + entry.j2 = j2; + entry.m2 = m2; + entry.j = j; + entry.m = m; + entry.value = coefficient_uncached(j1, m1, j2, m2, j, m); + entries_.push_back(entry); + } + } + } + } + } +} + +double ClebschGordanTable::factorial(const int value) +{ + if (value < 0) + { + return 0.0; + } + return std::tgamma(static_cast(value) + 1.0); +} + +bool ClebschGordanTable::allowed(const int j1, + const int m1, + const int j2, + const int m2, + const int j, + const int m) +{ + if (j1 < 0 || j2 < 0 || j < 0 || m1 < -j1 || m1 > j1 || m2 < -j2 || m2 > j2 || m < -j || m > j) + { + return false; + } + if ((j1 - m1) % 2 != 0 || (j2 - m2) % 2 != 0 || (j - m) % 2 != 0) + { + return false; + } + if ((j1 + j2 + j) % 2 != 0 || j < std::abs(j1 - j2) || j > j1 + j2) + { + return false; + } + return m == m1 + m2; +} + +double ClebschGordanTable::coefficient_uncached(const int j1, + const int m1, + const int j2, + const int m2, + const int j, + const int m) +{ + if (!allowed(j1, m1, j2, m2, j, m)) + { + return 0.0; + } + + const double delta = std::sqrt( + factorial((j1 + j2 - j) / 2) * factorial((j1 - j2 + j) / 2) + * factorial((-j1 + j2 + j) / 2) / factorial((j1 + j2 + j) / 2 + 1)); + const double prefactor = std::sqrt( + (j + 1.0) * factorial(half_sum(j1, m1)) * factorial(half_sum(j1, -m1)) + * factorial(half_sum(j2, m2)) * factorial(half_sum(j2, -m2)) + * factorial(half_sum(j, m)) * factorial(half_sum(j, -m))); + + double sum = 0.0; + const int zmin = std::max(0, std::max(-(j - j2 + m1) / 2, -(j - j1 - m2) / 2)); + const int zmax = std::min((j1 + j2 - j) / 2, + std::min((j1 - m1) / 2, (j2 + m2) / 2)); + for (int z = zmin; z <= zmax; ++z) + { + const int a = z; + const int b = (j1 + j2 - j) / 2 - z; + const int c = (j1 - m1) / 2 - z; + const int d = (j2 + m2) / 2 - z; + const int e = (j - j2 + m1) / 2 + z; + const int f = (j - j1 - m2) / 2 + z; + if (a < 0 || b < 0 || c < 0 || d < 0 || e < 0 || f < 0) + { + continue; + } + const double denominator = factorial(a) * factorial(b) * factorial(c) * factorial(d) * factorial(e) * factorial(f); + sum += (z % 2 == 0 ? 1.0 : -1.0) / denominator; + } + + return delta * prefactor * sum; +} + +const ClebschGordanTable::Entry* ClebschGordanTable::find(const int j1, + const int m1, + const int j2, + const int m2, + const int j, + const int m) const +{ + for (std::size_t index = 0; index < entries_.size(); ++index) + { + const Entry& entry = entries_[index]; + if (entry.j1 == j1 && entry.m1 == m1 && entry.j2 == j2 && entry.m2 == m2 && entry.j == j && entry.m == m) + { + return &entry; + } + } + return nullptr; +} + +double ClebschGordanTable::coefficient(const int j1, + const int m1, + const int j2, + const int m2, + const int j, + const int m) const +{ + const Entry* entry = find(j1, m1, j2, m2, j, m); + return entry == nullptr ? 0.0 : entry->value; +} + +double ClebschGordanTable::h_coefficient(const int j1, + const int m1, + const int mp1, + const int j2, + const int m2, + const int mp2, + const int j, + const int m, + const int mp) const +{ + return coefficient(j1, m1, j2, m2, j, m) * coefficient(j1, mp1, j2, mp2, j, mp); +} + +} // namespace SNAP +} // namespace ModuleMD diff --git a/source/source_md/snap/snap_clebsch_gordan.h b/source/source_md/snap/snap_clebsch_gordan.h new file mode 100644 index 00000000000..978c255d985 --- /dev/null +++ b/source/source_md/snap/snap_clebsch_gordan.h @@ -0,0 +1,58 @@ +#ifndef SNAP_CLEBSCH_GORDAN_H +#define SNAP_CLEBSCH_GORDAN_H + +#include + +namespace ModuleMD +{ +namespace SNAP +{ + +/** + * @brief Clebsch-Gordan coefficients indexed with doubled angular momenta. + * + * If the stored index is j, the physical angular momentum is j/2. The same + * convention is used for m and m'. + */ +class ClebschGordanTable +{ + public: + explicit ClebschGordanTable(int twojmax); + + double coefficient(int j1, int m1, int j2, int m2, int j, int m) const; + + double h_coefficient(int j1, + int m1, + int mp1, + int j2, + int m2, + int mp2, + int j, + int m, + int mp) const; + + private: + struct Entry + { + int j1; + int m1; + int j2; + int m2; + int j; + int m; + double value; + }; + + static bool allowed(int j1, int m1, int j2, int m2, int j, int m); + static double coefficient_uncached(int j1, int m1, int j2, int m2, int j, int m); + static double factorial(int value); + const Entry* find(int j1, int m1, int j2, int m2, int j, int m) const; + + int twojmax_; + std::vector entries_; +}; + +} // namespace SNAP +} // namespace ModuleMD + +#endif // SNAP_CLEBSCH_GORDAN_H diff --git a/source/source_md/snap/snap_descriptor.cpp b/source/source_md/snap/snap_descriptor.cpp new file mode 100644 index 00000000000..59c69f4f6a0 --- /dev/null +++ b/source/source_md/snap/snap_descriptor.cpp @@ -0,0 +1,510 @@ +#include "snap_descriptor.h" + +#include "source_base/constants.h" + +#include +#include +#include + +namespace ModuleMD +{ +namespace SNAP +{ + +namespace +{ +struct Dual +{ + double value; + double derivative; + + Dual(const double value_in = 0.0, const double derivative_in = 0.0) + : value(value_in), derivative(derivative_in) + { + } +}; + +Dual operator+(const Dual& left, const Dual& right) +{ + return Dual(left.value + right.value, left.derivative + right.derivative); +} + +Dual operator-(const Dual& left, const Dual& right) +{ + return Dual(left.value - right.value, left.derivative - right.derivative); +} + +Dual operator-(const Dual& value) +{ + return Dual(-value.value, -value.derivative); +} + +Dual operator*(const Dual& left, const Dual& right) +{ + return Dual(left.value * right.value, + left.derivative * right.value + left.value * right.derivative); +} + +Dual operator/(const Dual& left, const Dual& right) +{ + const double inverse = 1.0 / right.value; + return Dual(left.value * inverse, + (left.derivative * right.value - left.value * right.derivative) * inverse * inverse); +} + +Dual operator+(const Dual& left, const double right) +{ + return left + Dual(right); +} + +Dual operator-(const Dual& left, const double right) +{ + return left - Dual(right); +} + +Dual operator*(const Dual& left, const double right) +{ + return left * Dual(right); +} + +Dual operator*(const double left, const Dual& right) +{ + return Dual(left) * right; +} + +Dual operator/(const Dual& left, const double right) +{ + return left / Dual(right); +} + +Dual operator/(const double left, const Dual& right) +{ + return Dual(left) / right; +} + +Dual& operator*=(Dual& left, const Dual& right) +{ + left = left * right; + return left; +} + +Dual& operator+=(Dual& left, const Dual& right) +{ + left = left + right; + return left; +} + +Dual dual_sqrt(const Dual& value) +{ + const double root = std::sqrt(value.value); + return Dual(root, value.derivative / (2.0 * root)); +} + +Dual dual_cos(const Dual& value) +{ + return Dual(std::cos(value.value), -std::sin(value.value) * value.derivative); +} + +Dual dual_tan(const Dual& value) +{ + const double cosine = std::cos(value.value); + return Dual(std::tan(value.value), value.derivative / (cosine * cosine)); +} +} + +DescriptorEvaluator::DescriptorEvaluator(const ModelParameters& parameters) + : parameters_(parameters), cg_table_(parameters.twojmax), u_size_(0) +{ + std::string error; + if (!parameters_.valid(error)) + { + throw std::invalid_argument(error); + } + + u_block_.resize(static_cast(parameters_.twojmax + 1), 0); + for (int j = 0; j <= parameters_.twojmax; ++j) + { + u_block_[static_cast(j)] = u_size_; + u_size_ += static_cast((j + 1) * (j + 1)); + } + compute_rootpq(); + + for (int j1 = 0; j1 <= parameters_.twojmax; ++j1) + { + for (int j2 = 0; j2 <= j1; ++j2) + { + for (int j = j1 - j2; j <= std::min(parameters_.twojmax, j1 + j2); j += 2) + { + if (j >= j1) + { + BispectrumIndex index; + index.j1 = j1; + index.j2 = j2; + index.j = j; + bispectrum_indices_.push_back(index); + } + } + } + } +} + +void DescriptorEvaluator::compute_rootpq() +{ + const int dimension = parameters_.twojmax + 1; + rootpq_.assign(static_cast(dimension * dimension), 0.0); + for (int p = 1; p <= parameters_.twojmax; ++p) + { + for (int q = 1; q <= parameters_.twojmax; ++q) + { + rootpq_[static_cast(p * dimension + q)] = std::sqrt(static_cast(p) / q); + } + } +} + +std::size_t DescriptorEvaluator::u_index(const int j, const int ma, const int mb) const +{ + return u_block_[static_cast(j)] + static_cast(mb * (j + 1) + ma); +} + +double DescriptorEvaluator::cutoff(const double distance, const double cutoff_radius) const +{ + if (!parameters_.switch_flag) + { + return distance < cutoff_radius ? 1.0 : 0.0; + } + if (distance <= parameters_.rmin) + { + return 1.0; + } + if (distance >= cutoff_radius) + { + return 0.0; + } + const double angle = ModuleBase::PI * (distance - parameters_.rmin) + / (cutoff_radius - parameters_.rmin); + return 0.5 * (std::cos(angle) + 1.0); +} + +std::vector > DescriptorEvaluator::compute_u(const Neighbor& neighbor) const +{ + const double rsq = neighbor.x * neighbor.x + neighbor.y * neighbor.y + neighbor.z * neighbor.z; + const double distance = std::sqrt(rsq); + const double cutoff_radius = neighbor.cutoff_radius > 0.0 ? neighbor.cutoff_radius : parameters_.rcut; + std::vector > result(u_size_, std::complex(0.0, 0.0)); + if (distance <= 1.0e-14 || cutoff(distance, cutoff_radius) == 0.0) + { + return result; + } + + const double theta0 = (distance - parameters_.rmin) * parameters_.rfac0 * ModuleBase::PI + / (cutoff_radius - parameters_.rmin); + const double z0 = distance / std::tan(theta0); + const double r0inv = 1.0 / std::sqrt(rsq + z0 * z0); + const double ar = r0inv * z0; + const double ai = -r0inv * neighbor.z; + const double br = r0inv * neighbor.y; + const double bi = -r0inv * neighbor.x; + const int dimension = parameters_.twojmax + 1; + + result[0] = std::complex(1.0, 0.0); + for (int j = 1; j <= parameters_.twojmax; ++j) + { + for (int mb = 0; 2 * mb <= j; ++mb) + { + result[u_index(j, 0, mb)] = std::complex(0.0, 0.0); + for (int ma = 0; ma < j; ++ma) + { + const std::size_t current = u_index(j, ma, mb); + const std::size_t previous = u_index(j - 1, ma, mb); + const double first_root = rootpq_[static_cast((j - ma) * dimension + (j - mb))]; + const double second_root = rootpq_[static_cast((ma + 1) * dimension + (j - mb))]; + result[current] += first_root * std::complex(ar, -ai) * result[previous]; + result[current + 1] = -second_root * std::complex(br, -bi) * result[previous]; + } + } + + for (int mb = 0; 2 * mb <= j; ++mb) + { + for (int ma = 0; ma <= j; ++ma) + { + const std::size_t left = u_index(j, ma, mb); + const std::size_t right = u_index(j, j - ma, j - mb); + const double sign = ((ma - mb) % 2 == 0) ? 1.0 : -1.0; + result[right] = sign * std::conj(result[left]); + } + } + } + return result; +} + +UWithDerivative DescriptorEvaluator::compute_u_with_derivative(const Neighbor& neighbor, const int direction) const +{ + if (direction < 0 || direction > 2) + { + throw std::invalid_argument("SNAP derivative direction must be 0, 1, or 2."); + } + const Dual x(neighbor.x, direction == 0 ? 1.0 : 0.0); + const Dual y(neighbor.y, direction == 1 ? 1.0 : 0.0); + const Dual z(neighbor.z, direction == 2 ? 1.0 : 0.0); + const Dual rsq = x * x + y * y + z * z; + const Dual distance = dual_sqrt(rsq); + const double cutoff_radius = neighbor.cutoff_radius > 0.0 ? neighbor.cutoff_radius : parameters_.rcut; + + UWithDerivative result; + result.values.assign(u_size_, std::complex(0.0, 0.0)); + result.derivatives.assign(u_size_, std::complex(0.0, 0.0)); + if (distance.value <= 1.0e-14 || distance.value >= cutoff_radius) + { + return result; + } + + Dual scale; + if (!parameters_.switch_flag) + { + scale = Dual(1.0); + } + else if (distance.value <= parameters_.rmin) + { + scale = Dual(1.0); + } + else + { + const Dual angle = (distance - parameters_.rmin) * ModuleBase::PI + / (cutoff_radius - parameters_.rmin); + scale = 0.5 * (dual_cos(angle) + 1.0); + } + scale = scale * neighbor.weight; + + const Dual theta0 = (distance - parameters_.rmin) * parameters_.rfac0 * ModuleBase::PI + / (cutoff_radius - parameters_.rmin); + const Dual z0 = distance / dual_tan(theta0); + const Dual r0inv = 1.0 / dual_sqrt(rsq + z0 * z0); + const Dual ar = r0inv * z0; + const Dual ai = -r0inv * z; + const Dual br = r0inv * y; + const Dual bi = -r0inv * x; + std::vector > raw(u_size_, std::complex(Dual(0.0), Dual(0.0))); + raw[0] = std::complex(Dual(1.0), Dual(0.0)); + const int dimension = parameters_.twojmax + 1; + for (int j = 1; j <= parameters_.twojmax; ++j) + { + for (int mb = 0; 2 * mb <= j; ++mb) + { + raw[u_index(j, 0, mb)] = std::complex(Dual(0.0), Dual(0.0)); + for (int ma = 0; ma < j; ++ma) + { + const std::size_t current = u_index(j, ma, mb); + const std::size_t previous = u_index(j - 1, ma, mb); + const double first_root = rootpq_[static_cast((j - ma) * dimension + (j - mb))]; + const double second_root = rootpq_[static_cast((ma + 1) * dimension + (j - mb))]; + raw[current] += Dual(first_root) * std::complex(ar, -ai) * raw[previous]; + raw[current + 1] = Dual(-second_root) * std::complex(br, -bi) * raw[previous]; + } + } + for (int mb = 0; 2 * mb <= j; ++mb) + { + for (int ma = 0; ma <= j; ++ma) + { + const std::size_t left = u_index(j, ma, mb); + const std::size_t right = u_index(j, j - ma, j - mb); + const double sign = ((ma - mb) % 2 == 0) ? 1.0 : -1.0; + raw[right] = Dual(sign) * std::conj(raw[left]); + } + } + } + for (std::size_t i = 0; i < raw.size(); ++i) + { + const std::complex value = scale * raw[i]; + result.values[i] = std::complex(value.real().value, value.imag().value); + result.derivatives[i] = std::complex(value.real().derivative, value.imag().derivative); + } + return result; +} + +std::vector > DescriptorEvaluator::accumulate_u(const std::vector& neighbors) const +{ + std::vector > result(u_size_, std::complex(0.0, 0.0)); + for (int j = 0; j <= parameters_.twojmax; ++j) + { + for (int ma = 0; ma <= j; ++ma) + { + result[u_index(j, ma, ma)] = parameters_.wself; + } + } + + for (std::size_t index = 0; index < neighbors.size(); ++index) + { + const Neighbor& neighbor = neighbors[index]; + const double distance = std::sqrt(neighbor.x * neighbor.x + neighbor.y * neighbor.y + neighbor.z * neighbor.z); + const double cutoff_radius = neighbor.cutoff_radius > 0.0 ? neighbor.cutoff_radius : parameters_.rcut; + const double scale = cutoff(distance, cutoff_radius) * neighbor.weight; + if (scale == 0.0) + { + continue; + } + const std::vector > one_neighbor = compute_u(neighbor); + for (std::size_t i = 0; i < result.size(); ++i) + { + result[i] += scale * one_neighbor[i]; + } + } + return result; +} + +std::vector DescriptorEvaluator::compute_bispectrum(const std::vector >& u) const +{ + if (u.size() != u_size_) + { + throw std::invalid_argument("SNAP u array has an unexpected size."); + } + std::vector result(bispectrum_indices_.size(), 0.0); + const auto compute_z = [this, &u](const BispectrumIndex& index, const int ma, const int mb) { + std::complex z(0.0, 0.0); + const int m = 2 * ma - index.j; + const int mp = 2 * mb - index.j; + for (int ma1 = 0; ma1 <= index.j1; ++ma1) + { + const int m1 = 2 * ma1 - index.j1; + for (int ma2 = 0; ma2 <= index.j2; ++ma2) + { + const int m2 = 2 * ma2 - index.j2; + const double c1 = cg_table_.coefficient(index.j1, m1, index.j2, m2, index.j, m); + if (c1 == 0.0) + { + continue; + } + for (int mb1 = 0; mb1 <= index.j1; ++mb1) + { + const int mp1 = 2 * mb1 - index.j1; + for (int mb2 = 0; mb2 <= index.j2; ++mb2) + { + const int mp2 = 2 * mb2 - index.j2; + const double c2 = cg_table_.coefficient(index.j1, mp1, index.j2, mp2, index.j, mp); + if (c2 != 0.0) + { + z += c1 * c2 + * u[u_index(index.j1, ma1, mb1)] + * u[u_index(index.j2, ma2, mb2)]; + } + } + } + } + } + return z; + }; + for (std::size_t ib = 0; ib < bispectrum_indices_.size(); ++ib) + { + const BispectrumIndex& index = bispectrum_indices_[ib]; + std::complex value(0.0, 0.0); + for (int mb = 0; 2 * mb < index.j; ++mb) + { + for (int ma = 0; ma <= index.j; ++ma) + { + value += std::conj(u[u_index(index.j, ma, mb)]) * compute_z(index, ma, mb); + } + } + if (index.j % 2 == 0) + { + const int mb = index.j / 2; + for (int ma = 0; ma < mb; ++ma) + { + value += std::conj(u[u_index(index.j, ma, mb)]) * compute_z(index, ma, mb); + } + value += 0.5 * std::conj(u[u_index(index.j, mb, mb)]) * compute_z(index, mb, mb); + } + result[ib] = 2.0 * value.real() / (parameters_.bnorm_flag ? index.j + 1.0 : 1.0); + } + return result; +} + +std::vector DescriptorEvaluator::compute_bispectrum_derivative( + const std::vector >& u, + const std::vector >& du) const +{ + if (u.size() != u_size_ || du.size() != u_size_) + { + throw std::invalid_argument("SNAP u derivative array has an unexpected size."); + } + std::vector result(bispectrum_indices_.size(), 0.0); + const auto compute_z = [this, &u, &du](const BispectrumIndex& index, + const int ma, + const int mb, + std::complex& z, + std::complex& dz) { + z = std::complex(0.0, 0.0); + dz = std::complex(0.0, 0.0); + const int m = 2 * ma - index.j; + const int mp = 2 * mb - index.j; + for (int ma1 = 0; ma1 <= index.j1; ++ma1) + { + const int m1 = 2 * ma1 - index.j1; + for (int ma2 = 0; ma2 <= index.j2; ++ma2) + { + const int m2 = 2 * ma2 - index.j2; + const double c1 = cg_table_.coefficient(index.j1, m1, index.j2, m2, index.j, m); + if (c1 == 0.0) + { + continue; + } + for (int mb1 = 0; mb1 <= index.j1; ++mb1) + { + const int mp1 = 2 * mb1 - index.j1; + for (int mb2 = 0; mb2 <= index.j2; ++mb2) + { + const int mp2 = 2 * mb2 - index.j2; + const double c2 = cg_table_.coefficient(index.j1, mp1, index.j2, mp2, index.j, mp); + if (c2 == 0.0) + { + continue; + } + const double coefficient = c1 * c2; + const std::complex u1 = u[u_index(index.j1, ma1, mb1)]; + const std::complex u2 = u[u_index(index.j2, ma2, mb2)]; + const std::complex du1 = du[u_index(index.j1, ma1, mb1)]; + const std::complex du2 = du[u_index(index.j2, ma2, mb2)]; + z += coefficient * u1 * u2; + dz += coefficient * (du1 * u2 + u1 * du2); + } + } + } + } + }; + for (std::size_t ib = 0; ib < bispectrum_indices_.size(); ++ib) + { + const BispectrumIndex& index = bispectrum_indices_[ib]; + std::complex derivative(0.0, 0.0); + for (int mb = 0; 2 * mb < index.j; ++mb) + { + for (int ma = 0; ma <= index.j; ++ma) + { + std::complex z(0.0, 0.0); + std::complex dz(0.0, 0.0); + compute_z(index, ma, mb, z, dz); + derivative += std::conj(du[u_index(index.j, ma, mb)]) * z + + std::conj(u[u_index(index.j, ma, mb)]) * dz; + } + } + if (index.j % 2 == 0) + { + const int mb = index.j / 2; + for (int ma = 0; ma < mb; ++ma) + { + std::complex z(0.0, 0.0); + std::complex dz(0.0, 0.0); + compute_z(index, ma, mb, z, dz); + derivative += std::conj(du[u_index(index.j, ma, mb)]) * z + + std::conj(u[u_index(index.j, ma, mb)]) * dz; + } + std::complex z(0.0, 0.0); + std::complex dz(0.0, 0.0); + compute_z(index, mb, mb, z, dz); + derivative += 0.5 * (std::conj(du[u_index(index.j, mb, mb)]) * z + + std::conj(u[u_index(index.j, mb, mb)]) * dz); + } + result[ib] = 2.0 * derivative.real() / (parameters_.bnorm_flag ? index.j + 1.0 : 1.0); + } + return result; +} + +} // namespace SNAP +} // namespace ModuleMD diff --git a/source/source_md/snap/snap_descriptor.h b/source/source_md/snap/snap_descriptor.h new file mode 100644 index 00000000000..0add0846184 --- /dev/null +++ b/source/source_md/snap/snap_descriptor.h @@ -0,0 +1,79 @@ +#ifndef SNAP_DESCRIPTOR_H +#define SNAP_DESCRIPTOR_H + +#include "snap_clebsch_gordan.h" +#include "snap_model.h" + +#include +#include + +namespace ModuleMD +{ +namespace SNAP +{ + +struct Neighbor +{ + double x = 0.0; + double y = 0.0; + double z = 0.0; + double weight = 1.0; + double cutoff_radius = 0.0; +}; + +struct UWithDerivative +{ + std::vector > values; + std::vector > derivatives; +}; + +class DescriptorEvaluator +{ + public: + explicit DescriptorEvaluator(const ModelParameters& parameters); + + std::vector > compute_u(const Neighbor& neighbor) const; + + UWithDerivative compute_u_with_derivative(const Neighbor& neighbor, int direction) const; + + std::vector > accumulate_u(const std::vector& neighbors) const; + + std::vector compute_bispectrum(const std::vector >& u) const; + + std::vector compute_bispectrum_derivative(const std::vector >& u, + const std::vector >& du) const; + + std::size_t u_size() const + { + return u_size_; + } + + std::size_t bispectrum_size() const + { + return bispectrum_indices_.size(); + } + + private: + struct BispectrumIndex + { + int j1; + int j2; + int j; + }; + + std::size_t u_index(int j, int ma, int mb) const; + double cutoff(double distance, double cutoff_radius) const; + void compute_rootpq(); + + ModelParameters parameters_; + ClebschGordanTable cg_table_; + std::vector rootpq_; + std::vector u_block_; + std::vector bispectrum_indices_; + std::size_t u_size_; +}; + +} // namespace SNAP +} // namespace ModuleMD + +#endif // SNAP_DESCRIPTOR_H diff --git a/source/source_md/snap/snap_model.cpp b/source/source_md/snap/snap_model.cpp new file mode 100644 index 00000000000..968a76fed3c --- /dev/null +++ b/source/source_md/snap/snap_model.cpp @@ -0,0 +1,285 @@ +#include "snap_model.h" +#include +#include +#include +#include + +namespace +{ +bool next_data_line(std::istream& input, std::string& line) +{ + while (std::getline(input, line)) + { + const std::size_t comment = line.find('#'); + if (comment != std::string::npos) + { + line.erase(comment); + } + std::istringstream words(line); + std::string first; + if (words >> first) + { + return true; + } + } + return false; +} +} + +namespace ModuleMD +{ +namespace SNAP +{ + +bool ModelParameters::valid(std::string& error) const +{ + if (!std::isfinite(rcut) || rcut <= 0.0) + { + error = "SNAP cutoff must be finite and positive."; + return false; + } + if (!std::isfinite(rcutfac) || rcutfac <= 0.0) + { + error = "SNAP rcutfac must be finite and positive."; + return false; + } + if (!std::isfinite(rmin) || rmin < 0.0 || rmin >= rcut) + { + error = "SNAP rmin must satisfy 0 <= rmin < rcut."; + return false; + } + if (!std::isfinite(rfac0) || rfac0 <= 0.0) + { + error = "SNAP rfac0 must be finite and positive."; + return false; + } + if (twojmax < 0) + { + error = "SNAP twojmax must be non-negative."; + return false; + } + if (!std::isfinite(wself)) + { + error = "SNAP self weight must be finite."; + return false; + } + if (elements.empty() || element_weights.size() != elements.size()) + { + error = "SNAP element names and weights must be non-empty and have the same size."; + return false; + } + if (element_radii.size() != elements.size()) + { + error = "SNAP element names and radii must have the same size."; + return false; + } + for (std::size_t i = 0; i < element_weights.size(); ++i) + { + if (!std::isfinite(element_weights[i]) || !std::isfinite(element_radii[i]) || element_radii[i] <= 0.0) + { + error = "SNAP element weights must be finite."; + return false; + } + } + return true; +} + +bool ModelData::load(const std::string& coefficient_file, + const std::string& parameter_file, + const std::vector& requested_elements, + std::string& error) +{ + parameters = ModelParameters(); + parameters.rfac0 = 0.99363; + coefficients.clear(); + parameters.elements = requested_elements; + if (parameters.elements.empty()) + { + error = "SNAP requires at least one requested element."; + return false; + } + + std::ifstream coeff_stream(coefficient_file.c_str()); + if (!coeff_stream) + { + error = "Cannot open SNAP coefficient file: " + coefficient_file; + return false; + } + + std::string line; + if (!next_data_line(coeff_stream, line)) + { + error = "SNAP coefficient file is empty."; + return false; + } + std::istringstream header(line); + int block_count = 0; + int coefficient_count = 0; + if (!(header >> block_count >> coefficient_count) || block_count <= 0 || coefficient_count <= 0) + { + error = "Invalid SNAP coefficient file header."; + return false; + } + + std::vector found(parameters.elements.size(), false); + parameters.element_weights.assign(parameters.elements.size(), 0.0); + parameters.element_radii.assign(parameters.elements.size(), 0.0); + coefficients.assign(parameters.elements.size(), std::vector()); + for (int block = 0; block < block_count; ++block) + { + if (!next_data_line(coeff_stream, line)) + { + error = "SNAP coefficient file ended before all element blocks were read."; + return false; + } + std::istringstream element_line(line); + std::string element; + double radius = 0.0; + double weight = 0.0; + if (!(element_line >> element >> radius >> weight)) + { + error = "Invalid SNAP element line."; + return false; + } + std::size_t element_index = parameters.elements.size(); + for (std::size_t i = 0; i < parameters.elements.size(); ++i) + { + if (parameters.elements[i] == element) + { + element_index = i; + break; + } + } + std::vector values(static_cast(coefficient_count), 0.0); + for (int coefficient = 0; coefficient < coefficient_count; ++coefficient) + { + if (!next_data_line(coeff_stream, line)) + { + error = "SNAP coefficient file ended before all coefficients were read."; + return false; + } + std::istringstream value_line(line); + if (!(value_line >> values[static_cast(coefficient)])) + { + error = "Invalid SNAP coefficient value."; + return false; + } + } + if (element_index < parameters.elements.size()) + { + if (found[element_index]) + { + error = "Duplicate SNAP element block: " + element; + return false; + } + found[element_index] = true; + parameters.element_radii[element_index] = radius; + parameters.element_weights[element_index] = weight; + coefficients[element_index] = values; + } + } + for (std::size_t i = 0; i < found.size(); ++i) + { + if (!found[i]) + { + error = "SNAP coefficient file does not contain requested element: " + parameters.elements[i]; + return false; + } + } + + std::ifstream parameter_stream(parameter_file.c_str()); + if (!parameter_stream) + { + error = "Cannot open SNAP parameter file: " + parameter_file; + return false; + } + bool has_rcutfac = false; + bool has_twojmax = false; + while (next_data_line(parameter_stream, line)) + { + std::istringstream words(line); + std::string keyword; + words >> keyword; + if (keyword == "rcutfac") + { + has_rcutfac = static_cast(words >> parameters.rcutfac); + } + else if (keyword == "twojmax") + { + has_twojmax = static_cast(words >> parameters.twojmax); + } + else if (keyword == "rfac0") + { + words >> parameters.rfac0; + } + else if (keyword == "rmin0") + { + words >> parameters.rmin; + } + else if (keyword == "bnormflag") + { + int value = 0; + words >> value; + parameters.bnorm_flag = value != 0; + } + else if (keyword == "switchflag") + { + int value = 0; + words >> value; + parameters.switch_flag = value != 0; + } + else if (keyword == "bzeroflag") + { + int value = 0; + words >> value; + parameters.bzero_flag = value != 0; + } + else if (keyword == "quadraticflag") + { + int value = 0; + words >> value; + parameters.quadratic_flag = value != 0; + } + else if (keyword == "wselfallflag") + { + int value = 0; + words >> value; + parameters.wselfall_flag = value != 0; + } + else if (keyword == "chemflag") + { + int value = 0; + words >> value; + parameters.chem_flag = value != 0; + } + } + if (!has_rcutfac || !has_twojmax) + { + error = "SNAP parameter file must define rcutfac and twojmax."; + return false; + } + if (parameters.chem_flag) + { + error = "Chemical SNAP channels are not implemented in this CPU stage."; + return false; + } + double maximum_cutoff = 0.0; + for (std::size_t i = 0; i < parameters.element_radii.size(); ++i) + { + maximum_cutoff = std::max(maximum_cutoff, 2.0 * parameters.element_radii[i] * parameters.rcutfac); + } + parameters.rcut = maximum_cutoff; + return parameters.valid(error); +} + +std::size_t ModelData::coefficient_count() const +{ + if (coefficients.empty()) + { + return 0; + } + return coefficients[0].size(); +} + +} // namespace SNAP +} // namespace ModuleMD diff --git a/source/source_md/snap/snap_model.h b/source/source_md/snap/snap_model.h new file mode 100644 index 00000000000..356a1e9cd4f --- /dev/null +++ b/source/source_md/snap/snap_model.h @@ -0,0 +1,49 @@ +#ifndef SNAP_MODEL_H +#define SNAP_MODEL_H + +#include +#include + +namespace ModuleMD +{ +namespace SNAP +{ + +struct ModelParameters +{ + double rcut = 0.0; + double rcutfac = 0.0; + double rmin = 0.0; + double rfac0 = 0.0; + int twojmax = 0; + bool bnorm_flag = false; + bool chem_flag = false; + bool switch_flag = true; + bool bzero_flag = true; + bool quadratic_flag = false; + bool wselfall_flag = false; + double wself = 1.0; + std::vector elements; + std::vector element_weights; + std::vector element_radii; + + bool valid(std::string& error) const; +}; + +struct ModelData +{ + ModelParameters parameters; + std::vector > coefficients; + + bool load(const std::string& coefficient_file, + const std::string& parameter_file, + const std::vector& requested_elements, + std::string& error); + + std::size_t coefficient_count() const; +}; + +} // namespace SNAP +} // namespace ModuleMD + +#endif // SNAP_MODEL_H diff --git a/source/source_md/snap/test/CMakeLists.txt b/source/source_md/snap/test/CMakeLists.txt new file mode 100644 index 00000000000..72a5fc8f6c8 --- /dev/null +++ b/source/source_md/snap/test/CMakeLists.txt @@ -0,0 +1,21 @@ +AddTest( + TARGET MODULE_MD_SNAP_model + SOURCES test_snap_model.cpp ../snap_model.cpp +) + +AddTest( + TARGET MODULE_MD_SNAP_clebsch_gordan + SOURCES test_snap_clebsch_gordan.cpp ../snap_clebsch_gordan.cpp +) + +AddTest( + TARGET MODULE_MD_SNAP_descriptor + LIBS base device + SOURCES test_snap_descriptor.cpp ../snap_descriptor.cpp ../snap_model.cpp ../snap_clebsch_gordan.cpp +) + +AddTest( + TARGET MODULE_MD_SNAP_calculator + LIBS base device + SOURCES test_snap_calculator.cpp ../snap_calculator.cpp ../snap_descriptor.cpp ../snap_model.cpp ../snap_clebsch_gordan.cpp +) diff --git a/source/source_md/snap/test/test_snap_calculator.cpp b/source/source_md/snap/test/test_snap_calculator.cpp new file mode 100644 index 00000000000..498d6cd85eb --- /dev/null +++ b/source/source_md/snap/test/test_snap_calculator.cpp @@ -0,0 +1,85 @@ +#include "../snap_calculator.h" + +#include + +#include + +namespace +{ + +ModuleMD::SNAP::ModelData make_model() +{ + ModuleMD::SNAP::ModelData model; + model.parameters.rcut = 4.5; + model.parameters.rcutfac = 1.0; + model.parameters.rmin = 0.0; + model.parameters.rfac0 = 0.99363; + model.parameters.twojmax = 0; + model.parameters.elements.push_back("Si"); + model.parameters.element_weights.push_back(1.0); + model.parameters.element_radii.push_back(2.25); + model.coefficients.push_back(std::vector{2.0, 3.0}); + return model; +} + +TEST(SnapCalculator, ComputesLinearAtomicEnergy) +{ + const ModuleMD::SNAP::Calculator calculator(make_model()); + ModuleMD::SNAP::Neighbor neighbor; + neighbor.x = 1.0; + const ModuleMD::SNAP::EnergyResult result = + calculator.compute(std::vector(1, neighbor), 0); + + ASSERT_EQ(result.descriptor.size(), static_cast(1)); + EXPECT_TRUE(std::isfinite(result.descriptor[0])); + EXPECT_DOUBLE_EQ(result.energy, 2.0 + 3.0 * result.descriptor[0]); +} + +TEST(SnapCalculator, RejectsMismatchedCoefficientCount) +{ + ModuleMD::SNAP::ModelData model = make_model(); + model.coefficients[0].push_back(4.0); + EXPECT_THROW(ModuleMD::SNAP::Calculator calculator(model), std::invalid_argument); +} + +TEST(SnapCalculator, RejectsInvalidCentralElement) +{ + const ModuleMD::SNAP::Calculator calculator(make_model()); + EXPECT_THROW(calculator.compute(std::vector(), 1), std::out_of_range); +} + +TEST(SnapCalculator, FiniteDifferenceForcesConservePairContribution) +{ + const ModuleMD::SNAP::Calculator calculator(make_model()); + ModuleMD::SNAP::Neighbor neighbor; + neighbor.x = 1.0; + const ModuleMD::SNAP::ForceResult result = calculator.compute_with_finite_difference_force( + std::vector(1, neighbor), 0, 1.0e-5); + + for (int direction = 0; direction < 3; ++direction) + { + EXPECT_DOUBLE_EQ(result.center_force[static_cast(direction)] + + result.neighbor_forces[0][static_cast(direction)], + 0.0); + } +} + +TEST(SnapCalculator, AnalyticForceMatchesFiniteDifference) +{ + const ModuleMD::SNAP::Calculator calculator(make_model()); + ModuleMD::SNAP::Neighbor neighbor; + neighbor.x = 1.0; + neighbor.y = 0.4; + neighbor.z = -0.2; + const std::vector neighbors(1, neighbor); + const ModuleMD::SNAP::ForceResult analytic = calculator.compute_with_analytic_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult finite = calculator.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); + for (int direction = 0; direction < 3; ++direction) + { + EXPECT_NEAR(analytic.neighbor_forces[0][static_cast(direction)], + finite.neighbor_forces[0][static_cast(direction)], + 1.0e-6); + } +} + +} // namespace diff --git a/source/source_md/snap/test/test_snap_clebsch_gordan.cpp b/source/source_md/snap/test/test_snap_clebsch_gordan.cpp new file mode 100644 index 00000000000..0639ccabfa3 --- /dev/null +++ b/source/source_md/snap/test/test_snap_clebsch_gordan.cpp @@ -0,0 +1,32 @@ +#include "../snap_clebsch_gordan.h" + +#include + +#include + +namespace +{ + +TEST(SnapClebschGordan, HighestWeightCoefficientIsOne) +{ + const ModuleMD::SNAP::ClebschGordanTable table(2); + EXPECT_NEAR(table.coefficient(1, 1, 1, 1, 2, 2), 1.0, 1.0e-14); +} + +TEST(SnapClebschGordan, SingletHasExpectedSigns) +{ + const ModuleMD::SNAP::ClebschGordanTable table(2); + const double value = 1.0 / std::sqrt(2.0); + EXPECT_NEAR(table.coefficient(1, 1, 1, -1, 0, 0), value, 1.0e-14); + EXPECT_NEAR(table.coefficient(1, -1, 1, 1, 0, 0), -value, 1.0e-14); +} + +TEST(SnapClebschGordan, SelectionRulesReturnZero) +{ + const ModuleMD::SNAP::ClebschGordanTable table(2); + EXPECT_DOUBLE_EQ(table.coefficient(1, 1, 1, 1, 0, 0), 0.0); + EXPECT_DOUBLE_EQ(table.coefficient(1, 1, 1, -1, 2, 1), 0.0); + EXPECT_DOUBLE_EQ(table.h_coefficient(1, 1, 1, 1, -1, -1, 0, 0, 0), 0.5); +} + +} // namespace diff --git a/source/source_md/snap/test/test_snap_descriptor.cpp b/source/source_md/snap/test/test_snap_descriptor.cpp new file mode 100644 index 00000000000..0514dd4f6ae --- /dev/null +++ b/source/source_md/snap/test/test_snap_descriptor.cpp @@ -0,0 +1,103 @@ +#include "../snap_descriptor.h" + +#include + +#include + +namespace +{ + +ModuleMD::SNAP::ModelParameters make_parameters() +{ + ModuleMD::SNAP::ModelParameters parameters; + parameters.rcut = 4.5; + parameters.rcutfac = 1.0; + parameters.rmin = 0.0; + parameters.rfac0 = 0.99363; + parameters.twojmax = 2; + parameters.bzero_flag = false; + parameters.elements.push_back("Si"); + parameters.element_weights.push_back(1.0); + parameters.element_radii.push_back(2.25); + return parameters; +} + +TEST(SnapDescriptor, AllocatesExpectedArraySizes) +{ + const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); + EXPECT_EQ(evaluator.u_size(), static_cast(1 * 1 + 2 * 2 + 3 * 3)); + EXPECT_EQ(evaluator.bispectrum_size(), static_cast(5)); +} + +TEST(SnapDescriptor, SelfContributionIsDiagonal) +{ + const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); + const std::vector neighbors; + const std::vector > u = evaluator.accumulate_u(neighbors); + + EXPECT_DOUBLE_EQ(u[0].real(), 1.0); + EXPECT_DOUBLE_EQ(u[0].imag(), 0.0); + EXPECT_DOUBLE_EQ(u[4].real(), 1.0); + EXPECT_DOUBLE_EQ(u[4].imag(), 0.0); + EXPECT_DOUBLE_EQ(u[13].real(), 1.0); + EXPECT_DOUBLE_EQ(u[13].imag(), 0.0); +} + +TEST(SnapDescriptor, OutsideCutoffDoesNotChangeEnvironment) +{ + const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); + ModuleMD::SNAP::Neighbor neighbor; + neighbor.x = 5.0; + const std::vector neighbors(1, neighbor); + const std::vector > u = evaluator.accumulate_u(neighbors); + const std::vector > self = evaluator.accumulate_u(std::vector()); + + ASSERT_EQ(u.size(), self.size()); + for (std::size_t i = 0; i < u.size(); ++i) + { + EXPECT_NEAR(u[i].real(), self[i].real(), 1.0e-14); + EXPECT_NEAR(u[i].imag(), self[i].imag(), 1.0e-14); + } +} + +TEST(SnapDescriptor, BispectrumIsFinite) +{ + const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); + ModuleMD::SNAP::Neighbor neighbor; + neighbor.x = 1.2; + neighbor.y = 0.4; + neighbor.z = -0.8; + const std::vector > u = evaluator.accumulate_u(std::vector(1, neighbor)); + const std::vector bispectrum = evaluator.compute_bispectrum(u); + + for (std::size_t i = 0; i < bispectrum.size(); ++i) + { + EXPECT_TRUE(std::isfinite(bispectrum[i])); + } +} + +TEST(SnapDescriptor, MatchesLammpsSingleElementReference) +{ + const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); + const double positions[3][3] = {{1.0, 1.0, 1.0}, {2.0, 1.0, 1.0}, {1.0, 3.0, 1.0}}; + std::vector neighbors; + for (int atom = 1; atom < 3; ++atom) + { + ModuleMD::SNAP::Neighbor neighbor; + neighbor.x = positions[atom][0] - positions[0][0]; + neighbor.y = positions[atom][1] - positions[0][1]; + neighbor.z = positions[atom][2] - positions[0][2]; + neighbor.cutoff_radius = 4.0; + neighbors.push_back(neighbor); + } + const std::vector bispectrum = evaluator.compute_bispectrum(evaluator.accumulate_u(neighbors)); + const double reference[5] = { + 13.0368348609, 15.0992648922, 11.7631725456, 13.7069739819, 6.07477849248}; + ASSERT_EQ(bispectrum.size(), static_cast(5)); + for (int index = 0; index < 5; ++index) + { + EXPECT_NEAR(bispectrum[static_cast(index)], reference[index], 1.0e-9); + } +} + +} // namespace diff --git a/source/source_md/snap/test/test_snap_model.cpp b/source/source_md/snap/test/test_snap_model.cpp new file mode 100644 index 00000000000..f20c83928b7 --- /dev/null +++ b/source/source_md/snap/test/test_snap_model.cpp @@ -0,0 +1,93 @@ +#include "../snap_model.h" + +#include + +#include +#include + +namespace +{ + +TEST(SnapModel, AcceptsCompleteParameters) +{ + ModuleMD::SNAP::ModelParameters parameters; + parameters.rcut = 4.5; + parameters.rcutfac = 1.0; + parameters.rmin = 0.0; + parameters.rfac0 = 0.99363; + parameters.twojmax = 8; + parameters.elements.push_back("Si"); + parameters.element_weights.push_back(1.0); + parameters.element_radii.push_back(2.25); + + std::string error; + EXPECT_TRUE(parameters.valid(error)); + EXPECT_TRUE(error.empty()); +} + +TEST(SnapModel, RejectsInconsistentElementData) +{ + ModuleMD::SNAP::ModelParameters parameters; + parameters.rcut = 4.5; + parameters.rcutfac = 1.0; + parameters.rmin = 0.0; + parameters.rfac0 = 0.99363; + parameters.elements.push_back("Si"); + parameters.element_radii.push_back(2.25); + + std::string error; + EXPECT_FALSE(parameters.valid(error)); + EXPECT_FALSE(error.empty()); +} + +TEST(SnapModel, RejectsInvalidRadialRange) +{ + ModuleMD::SNAP::ModelParameters parameters; + parameters.rcut = 3.0; + parameters.rcutfac = 1.0; + parameters.rmin = 3.0; + parameters.rfac0 = 1.0; + parameters.elements.push_back("Si"); + parameters.element_weights.push_back(1.0); + parameters.element_radii.push_back(2.25); + + std::string error; + EXPECT_FALSE(parameters.valid(error)); + EXPECT_FALSE(error.empty()); +} + +TEST(SnapModel, LoadsLammpsStyleCoefficientAndParameterFiles) +{ + const std::string coefficient_file = "/tmp/snap_coeff_test.txt"; + const std::string parameter_file = "/tmp/snap_param_test.txt"; + { + std::ofstream output(coefficient_file.c_str()); + output << "1 3\n"; + output << "Si 2.25 1.0\n"; + output << "-0.5\n1.25\n2.5\n"; + } + { + std::ofstream output(parameter_file.c_str()); + output << "rcutfac 1.2\n"; + output << "twojmax 4\n"; + output << "rfac0 0.99363\n"; + output << "rmin0 0.0\n"; + output << "bnormflag 0\n"; + output << "chemflag 0\n"; + } + + ModuleMD::SNAP::ModelData model; + std::string error; + EXPECT_TRUE(model.load(coefficient_file, parameter_file, std::vector(1, "Si"), error)); + EXPECT_TRUE(error.empty()); + ASSERT_EQ(model.coefficient_count(), static_cast(3)); + EXPECT_DOUBLE_EQ(model.parameters.element_weights[0], 1.0); + EXPECT_DOUBLE_EQ(model.parameters.element_radii[0], 2.25); + EXPECT_DOUBLE_EQ(model.parameters.rcut, 5.4); + EXPECT_DOUBLE_EQ(model.coefficients[0][1], 1.25); + + std::remove(coefficient_file.c_str()); + std::remove(parameter_file.c_str()); +} + +} // namespace From 3c456f7f17280ec4c00965a4ac1099e644c12be5 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Thu, 29 Oct 2026 17:47:57 +0800 Subject: [PATCH 02/33] feat: add CPU SNAP potential support --- source/Makefile.Objects | 6 + source/source_esolver/esolver_factory.cpp | 3 +- source/source_esolver/esolver_snap.cpp | 36 +++- source/source_esolver/esolver_snap.h | 6 +- source/source_md/snap/snap_calculator.cpp | 23 ++- source/source_md/snap/snap_descriptor.cpp | 157 +++++++++++++----- source/source_md/snap/snap_descriptor.h | 9 + source/source_md/snap/snap_model.cpp | 68 ++++++-- .../snap/test/test_snap_calculator.cpp | 85 ++++++++++ .../source_md/snap/test/test_snap_model.cpp | 82 ++++++++- tests/04_FF/102_SNAP_minimal/INPUT | 12 ++ tests/04_FF/102_SNAP_minimal/README | 5 + tests/04_FF/102_SNAP_minimal/STRU | 19 +++ tests/04_FF/102_SNAP_minimal/result.ref | 5 + tests/04_FF/102_SNAP_minimal/snapcoeff | 61 +++++++ tests/04_FF/102_SNAP_minimal/snapparam | 9 + tests/04_FF/CASES_CPU.txt | 1 + 17 files changed, 515 insertions(+), 72 deletions(-) create mode 100644 tests/04_FF/102_SNAP_minimal/INPUT create mode 100644 tests/04_FF/102_SNAP_minimal/README create mode 100644 tests/04_FF/102_SNAP_minimal/STRU create mode 100644 tests/04_FF/102_SNAP_minimal/result.ref create mode 100644 tests/04_FF/102_SNAP_minimal/snapcoeff create mode 100644 tests/04_FF/102_SNAP_minimal/snapparam diff --git a/source/Makefile.Objects b/source/Makefile.Objects index b2361a72e26..12305919666 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -32,6 +32,7 @@ VPATH=./src_global:\ ./source_base/module_out:\ ./source_md:\ ./source_md/module_plumed:\ +./source_md/snap:\ ./source_basis/module_pw:\ ./source_base/module_fft:\ ./source_esolver:\ @@ -336,6 +337,7 @@ OBJS_ESOLVER=esolver_factory.o\ esolver_lj.o\ esolver_dp.o\ esolver_nep.o\ + esolver_snap.o\ esolver_of.o\ esolver_of_tddft.o\ esolver_of_interface.o\ @@ -536,6 +538,10 @@ OBJS_MD=fire.o\ nhchain.o\ plumed_interface.o\ run_md.o\ + snap/snap_calculator.o\ + snap/snap_descriptor.o\ + snap/snap_model.o\ + snap/snap_clebsch_gordan.o\ verlet.o\ OBJS_NEIGHBOR=sltk_atom.o\ diff --git a/source/source_esolver/esolver_factory.cpp b/source/source_esolver/esolver_factory.cpp index c3bfdf9104a..44ed98fb4f3 100644 --- a/source/source_esolver/esolver_factory.cpp +++ b/source/source_esolver/esolver_factory.cpp @@ -5,6 +5,7 @@ #include "esolver_dfpt_pw.h" #include "esolver_sdft_pw.h" #include "esolver_ks_pw_tddft.h" +#include "source_base/global_variable.h" #include "source_base/module_device/device.h" #include "source_hamilt/module_xc/general_exx_info.h" #include "source_io/module_parameter/parameter.h" @@ -397,7 +398,7 @@ ESolver* init_esolver(const Input_para& inp) } else if (esolver_type == "snap_pot") { - return new ESolver_SNAP(PARAM.mdp.pot_file, PARAM.mdp.snap_param_file); + return new ESolver_SNAP(inp.mdp.pot_file, inp.mdp.snap_param_file, GlobalV::ofs_running); } throw std::invalid_argument("esolver_type = " + std::string(esolver_type) + ". Wrong in " + std::string(__FILE__) + " line " + std::to_string(__LINE__)); diff --git a/source/source_esolver/esolver_snap.cpp b/source/source_esolver/esolver_snap.cpp index c77916756b2..f3f3d979054 100644 --- a/source/source_esolver/esolver_snap.cpp +++ b/source/source_esolver/esolver_snap.cpp @@ -35,12 +35,15 @@ ModuleMD::SNAP::Neighbor make_neighbor(const NeighborAtom& center, result.cutoff_radius = (parameters.element_radii[static_cast(center.atom_type)] + parameters.element_radii[static_cast(neighbor.atom_type)]) * parameters.rcutfac; + result.element_index = static_cast(neighbor.atom_type); return result; } } -ESolver_SNAP::ESolver_SNAP(const std::string& coefficient_file, const std::string& parameter_file) - : coefficient_file_(coefficient_file), parameter_file_(parameter_file) +ESolver_SNAP::ESolver_SNAP(const std::string& coefficient_file, + const std::string& parameter_file, + std::ofstream& running_log) + : coefficient_file_(coefficient_file), parameter_file_(parameter_file), running_log_(running_log) { classname = "ESolver_SNAP"; } @@ -251,18 +254,43 @@ void ESolver_SNAP::cal_force(BaseCell& cell, ModuleBase::matrix& force) return; } force = snap_force_; + ModuleIO::print_force(running_log_, + static_cast(cell), + "TOTAL-FORCE (eV/Angstrom)", + force, + false); } void ESolver_SNAP::cal_stress(BaseCell& cell, ModuleBase::matrix& stress) { - static_cast(cell); stress = snap_virial_; + + if (cell.kind() == BaseCell::Kind::unitcell) + { + ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, running_log_); + } + else + { +#ifdef __MPI + if (static_cast(cell).mpi_rank() == 0) +#endif + { + ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, running_log_); + } + } + + const double unit_transform = ModuleBase::RYDBERG_SI / pow(ModuleBase::BOHR_RADIUS_SI, 3) * 1.0e-8; + const double external_stress[3] = {inp_->press1, inp_->press2, inp_->press3}; + for (int i = 0; i < 3; ++i) + { + stress(i, i) -= external_stress[i] / unit_transform; + } } void ESolver_SNAP::after_all_runners(BaseCell& cell) { static_cast(cell); - GlobalV::ofs_running << "\n !FINAL_ETOT_IS " << snap_potential_ * ModuleBase::Ry_to_eV << " eV\n"; + running_log_ << "\n !FINAL_ETOT_IS " << snap_potential_ * ModuleBase::Ry_to_eV << " eV\n"; } } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_snap.h b/source/source_esolver/esolver_snap.h index c4c7aba2cdf..8dfeacaf0b6 100644 --- a/source/source_esolver/esolver_snap.h +++ b/source/source_esolver/esolver_snap.h @@ -4,6 +4,7 @@ #include "esolver.h" #include "source_md/snap/snap_calculator.h" +#include #include #include #include @@ -14,7 +15,9 @@ namespace ModuleESolver class ESolver_SNAP : public ESolver { public: - ESolver_SNAP(const std::string& coefficient_file, const std::string& parameter_file); + ESolver_SNAP(const std::string& coefficient_file, + const std::string& parameter_file, + std::ofstream& running_log); void before_all_runners(BaseCell& cell, const Input_para& inp) override; void runner(BaseCell& cell, int istep) override; @@ -28,6 +31,7 @@ class ESolver_SNAP : public ESolver std::string coefficient_file_; std::string parameter_file_; + std::ofstream& running_log_; ModuleMD::SNAP::ModelData model_; std::unique_ptr calculator_; double snap_potential_ = 0.0; diff --git a/source/source_md/snap/snap_calculator.cpp b/source/source_md/snap/snap_calculator.cpp index e2fb8843627..c8b5dac9745 100644 --- a/source/source_md/snap/snap_calculator.cpp +++ b/source/source_md/snap/snap_calculator.cpp @@ -8,8 +8,12 @@ namespace SNAP { Calculator::Calculator(const ModelData& model) - : model_(model), descriptor_evaluator_(model.parameters), descriptor_size_(descriptor_evaluator_.bispectrum_size()) + : model_(model), + descriptor_evaluator_(model.parameters), + descriptor_size_(0) { + const std::size_t channels = descriptor_evaluator_.channel_count(); + descriptor_size_ = descriptor_evaluator_.bispectrum_size() * channels * channels * channels; if (model_.coefficients.size() != model_.parameters.elements.size()) { throw std::invalid_argument("SNAP coefficient blocks do not match the element list."); @@ -35,11 +39,13 @@ EnergyResult Calculator::compute(const std::vector& neighbors, const s } EnergyResult result; - result.descriptor = descriptor_evaluator_.compute_bispectrum(descriptor_evaluator_.accumulate_u(neighbors)); + result.descriptor = descriptor_evaluator_.compute_bispectrum( + descriptor_evaluator_.accumulate_u(neighbors, central_element)); if (model_.parameters.bzero_flag) { const std::vector bzero = - descriptor_evaluator_.compute_bispectrum(descriptor_evaluator_.accumulate_u(std::vector())); + descriptor_evaluator_.compute_bispectrum( + descriptor_evaluator_.accumulate_u(std::vector(), central_element)); for (std::size_t index = 0; index < result.descriptor.size(); ++index) { result.descriptor[index] -= bzero[index]; @@ -84,11 +90,16 @@ ForceResult Calculator::compute_with_analytic_force(const std::vector& { const UWithDerivative u_derivative = descriptor_evaluator_.compute_u_with_derivative(neighbors[neighbor_index], direction); - std::vector > u = descriptor_evaluator_.accumulate_u(neighbors); + std::vector > u = descriptor_evaluator_.accumulate_u(neighbors, central_element); std::vector > du(u.size(), std::complex(0.0, 0.0)); - for (std::size_t index = 0; index < du.size(); ++index) + const std::size_t derivative_offset = model_.parameters.chem_flag + ? neighbors[neighbor_index].element_index + * descriptor_evaluator_.u_size() + : 0; + const std::vector >& one_neighbor_derivative = u_derivative.derivatives; + for (std::size_t index = 0; index < one_neighbor_derivative.size(); ++index) { - du[index] = u_derivative.derivatives[index]; + du[derivative_offset + index] = one_neighbor_derivative[index]; } const std::vector db = descriptor_evaluator_.compute_bispectrum_derivative(u, du); double derivative = 0.0; diff --git a/source/source_md/snap/snap_descriptor.cpp b/source/source_md/snap/snap_descriptor.cpp index 59c69f4f6a0..daf9f6f95e5 100644 --- a/source/source_md/snap/snap_descriptor.cpp +++ b/source/source_md/snap/snap_descriptor.cpp @@ -323,18 +323,42 @@ UWithDerivative DescriptorEvaluator::compute_u_with_derivative(const Neighbor& n std::vector > DescriptorEvaluator::accumulate_u(const std::vector& neighbors) const { - std::vector > result(u_size_, std::complex(0.0, 0.0)); - for (int j = 0; j <= parameters_.twojmax; ++j) + return accumulate_u(neighbors, 0); +} + +std::vector > DescriptorEvaluator::accumulate_u(const std::vector& neighbors, + const std::size_t central_element) const +{ + const std::size_t channels = channel_count(); + const std::size_t self_channel = parameters_.chem_flag ? central_element : 0; + if (self_channel >= channels) { - for (int ma = 0; ma <= j; ++ma) + throw std::out_of_range("SNAP central element is outside the descriptor channels."); + } + std::vector > result(channels * u_size_, std::complex(0.0, 0.0)); + for (std::size_t channel = 0; channel < channels; ++channel) + { + if (channel != self_channel && !parameters_.wselfall_flag) { - result[u_index(j, ma, ma)] = parameters_.wself; + continue; + } + for (int j = 0; j <= parameters_.twojmax; ++j) + { + for (int ma = 0; ma <= j; ++ma) + { + result[channel * u_size_ + u_index(j, ma, ma)] = parameters_.wself; + } } } for (std::size_t index = 0; index < neighbors.size(); ++index) { const Neighbor& neighbor = neighbors[index]; + const std::size_t channel = parameters_.chem_flag ? neighbor.element_index : 0; + if (channel >= channels) + { + throw std::out_of_range("SNAP neighbor element is outside the descriptor channels."); + } const double distance = std::sqrt(neighbor.x * neighbor.x + neighbor.y * neighbor.y + neighbor.z * neighbor.z); const double cutoff_radius = neighbor.cutoff_radius > 0.0 ? neighbor.cutoff_radius : parameters_.rcut; const double scale = cutoff(distance, cutoff_radius) * neighbor.weight; @@ -343,9 +367,10 @@ std::vector > DescriptorEvaluator::accumulate_u(const std:: continue; } const std::vector > one_neighbor = compute_u(neighbor); - for (std::size_t i = 0; i < result.size(); ++i) + const std::size_t offset = channel * u_size_; + for (std::size_t i = 0; i < one_neighbor.size(); ++i) { - result[i] += scale * one_neighbor[i]; + result[offset + i] += scale * one_neighbor[i]; } } return result; @@ -353,12 +378,22 @@ std::vector > DescriptorEvaluator::accumulate_u(const std:: std::vector DescriptorEvaluator::compute_bispectrum(const std::vector >& u) const { - if (u.size() != u_size_) + const std::size_t channels = channel_count(); + if (u.size() != channels * u_size_) { throw std::invalid_argument("SNAP u array has an unexpected size."); } - std::vector result(bispectrum_indices_.size(), 0.0); - const auto compute_z = [this, &u](const BispectrumIndex& index, const int ma, const int mb) { + const std::size_t bispectrum_size = bispectrum_indices_.size(); + std::vector result(channels * channels * channels * bispectrum_size, 0.0); + const auto compute_one = [this, &u](const std::size_t first_channel, + const std::size_t second_channel, + const std::size_t third_channel, + const std::size_t bispectrum_index) { + const BispectrumIndex& index = bispectrum_indices_[bispectrum_index]; + const std::size_t first_offset = first_channel * u_size_; + const std::size_t second_offset = second_channel * u_size_; + const std::size_t third_offset = third_channel * u_size_; + const auto compute_z = [this, &u, &index, first_offset, second_offset](const int ma, const int mb) { std::complex z(0.0, 0.0); const int m = 2 * ma - index.j; const int mp = 2 * mb - index.j; @@ -383,8 +418,8 @@ std::vector DescriptorEvaluator::compute_bispectrum(const std::vector DescriptorEvaluator::compute_bispectrum(const std::vector value(0.0, 0.0); for (int mb = 0; 2 * mb < index.j; ++mb) { for (int ma = 0; ma <= index.j; ++ma) { - value += std::conj(u[u_index(index.j, ma, mb)]) * compute_z(index, ma, mb); + value += std::conj(u[third_offset + u_index(index.j, ma, mb)]) * compute_z(ma, mb); } } if (index.j % 2 == 0) @@ -408,11 +440,26 @@ std::vector DescriptorEvaluator::compute_bispectrum(const std::vector DescriptorEvaluator::compute_bispectrum_derivative( const std::vector >& u, const std::vector >& du) const { - if (u.size() != u_size_ || du.size() != u_size_) + const std::size_t channels = channel_count(); + if (u.size() != channels * u_size_ || du.size() != channels * u_size_) { throw std::invalid_argument("SNAP u derivative array has an unexpected size."); } - std::vector result(bispectrum_indices_.size(), 0.0); - const auto compute_z = [this, &u, &du](const BispectrumIndex& index, - const int ma, - const int mb, - std::complex& z, - std::complex& dz) { + const std::size_t bispectrum_size = bispectrum_indices_.size(); + std::vector result(channels * channels * channels * bispectrum_size, 0.0); + const auto compute_one = [this, &u, &du](const std::size_t first_channel, + const std::size_t second_channel, + const std::size_t third_channel, + const std::size_t bispectrum_index) { + const BispectrumIndex& index = bispectrum_indices_[bispectrum_index]; + const std::size_t first_offset = first_channel * u_size_; + const std::size_t second_offset = second_channel * u_size_; + const std::size_t third_offset = third_channel * u_size_; + const auto compute_z = [this, &u, &du, &index, first_offset, second_offset](const int ma, + const int mb, + std::complex& z, + std::complex& dz) { z = std::complex(0.0, 0.0); dz = std::complex(0.0, 0.0); const int m = 2 * ma - index.j; @@ -458,20 +514,17 @@ std::vector DescriptorEvaluator::compute_bispectrum_derivative( continue; } const double coefficient = c1 * c2; - const std::complex u1 = u[u_index(index.j1, ma1, mb1)]; - const std::complex u2 = u[u_index(index.j2, ma2, mb2)]; - const std::complex du1 = du[u_index(index.j1, ma1, mb1)]; - const std::complex du2 = du[u_index(index.j2, ma2, mb2)]; + const std::complex u1 = u[first_offset + u_index(index.j1, ma1, mb1)]; + const std::complex u2 = u[second_offset + u_index(index.j2, ma2, mb2)]; + const std::complex du1 = du[first_offset + u_index(index.j1, ma1, mb1)]; + const std::complex du2 = du[second_offset + u_index(index.j2, ma2, mb2)]; z += coefficient * u1 * u2; dz += coefficient * (du1 * u2 + u1 * du2); } } } } - }; - for (std::size_t ib = 0; ib < bispectrum_indices_.size(); ++ib) - { - const BispectrumIndex& index = bispectrum_indices_[ib]; + }; std::complex derivative(0.0, 0.0); for (int mb = 0; 2 * mb < index.j; ++mb) { @@ -479,9 +532,10 @@ std::vector DescriptorEvaluator::compute_bispectrum_derivative( { std::complex z(0.0, 0.0); std::complex dz(0.0, 0.0); - compute_z(index, ma, mb, z, dz); - derivative += std::conj(du[u_index(index.j, ma, mb)]) * z - + std::conj(u[u_index(index.j, ma, mb)]) * dz; + compute_z(ma, mb, z, dz); + const std::complex du3 = du[third_offset + u_index(index.j, ma, mb)]; + derivative += std::conj(du3) * z + + std::conj(u[third_offset + u_index(index.j, ma, mb)]) * dz; } } if (index.j % 2 == 0) @@ -491,17 +545,34 @@ std::vector DescriptorEvaluator::compute_bispectrum_derivative( { std::complex z(0.0, 0.0); std::complex dz(0.0, 0.0); - compute_z(index, ma, mb, z, dz); - derivative += std::conj(du[u_index(index.j, ma, mb)]) * z - + std::conj(u[u_index(index.j, ma, mb)]) * dz; + compute_z(ma, mb, z, dz); + const std::complex du3 = du[third_offset + u_index(index.j, ma, mb)]; + derivative += std::conj(du3) * z + + std::conj(u[third_offset + u_index(index.j, ma, mb)]) * dz; } std::complex z(0.0, 0.0); std::complex dz(0.0, 0.0); - compute_z(index, mb, mb, z, dz); - derivative += 0.5 * (std::conj(du[u_index(index.j, mb, mb)]) * z - + std::conj(u[u_index(index.j, mb, mb)]) * dz); + compute_z(mb, mb, z, dz); + const std::complex du3 = du[third_offset + u_index(index.j, mb, mb)]; + derivative += 0.5 * (std::conj(du3) * z + + std::conj(u[third_offset + u_index(index.j, mb, mb)]) * dz); + } + return 2.0 * derivative.real() / (parameters_.bnorm_flag ? index.j + 1.0 : 1.0); + }; + for (std::size_t first_channel = 0; first_channel < channels; ++first_channel) + { + for (std::size_t second_channel = 0; second_channel < channels; ++second_channel) + { + for (std::size_t third_channel = 0; third_channel < channels; ++third_channel) + { + const std::size_t triple = (first_channel * channels + second_channel) * channels + third_channel; + for (std::size_t ib = 0; ib < bispectrum_size; ++ib) + { + result[triple * bispectrum_size + ib] + = compute_one(first_channel, second_channel, third_channel, ib); + } + } } - result[ib] = 2.0 * derivative.real() / (parameters_.bnorm_flag ? index.j + 1.0 : 1.0); } return result; } diff --git a/source/source_md/snap/snap_descriptor.h b/source/source_md/snap/snap_descriptor.h index 0add0846184..e12acaedf42 100644 --- a/source/source_md/snap/snap_descriptor.h +++ b/source/source_md/snap/snap_descriptor.h @@ -19,6 +19,7 @@ struct Neighbor double z = 0.0; double weight = 1.0; double cutoff_radius = 0.0; + std::size_t element_index = 0; }; struct UWithDerivative @@ -38,6 +39,9 @@ class DescriptorEvaluator std::vector > accumulate_u(const std::vector& neighbors) const; + std::vector > accumulate_u(const std::vector& neighbors, + std::size_t central_element) const; + std::vector compute_bispectrum(const std::vector >& u) const; std::vector compute_bispectrum_derivative(const std::vector >& u, @@ -53,6 +57,11 @@ class DescriptorEvaluator return bispectrum_indices_.size(); } + std::size_t channel_count() const + { + return parameters_.chem_flag ? parameters_.elements.size() : 1; + } + private: struct BispectrumIndex { diff --git a/source/source_md/snap/snap_model.cpp b/source/source_md/snap/snap_model.cpp index 968a76fed3c..4c62c864265 100644 --- a/source/source_md/snap/snap_model.cpp +++ b/source/source_md/snap/snap_model.cpp @@ -24,6 +24,17 @@ bool next_data_line(std::istream& input, std::string& line) } return false; } + +template +bool read_parameter_value(std::istringstream& words, T& value, const std::string& keyword, std::string& error) +{ + if (!(words >> value) || words.fail()) + { + error = "Invalid SNAP parameter value for keyword: " + keyword; + return false; + } + return true; +} } namespace ModuleMD @@ -202,54 +213,86 @@ bool ModelData::load(const std::string& coefficient_file, words >> keyword; if (keyword == "rcutfac") { - has_rcutfac = static_cast(words >> parameters.rcutfac); + if (!read_parameter_value(words, parameters.rcutfac, keyword, error)) + { + return false; + } + has_rcutfac = true; } else if (keyword == "twojmax") { - has_twojmax = static_cast(words >> parameters.twojmax); + if (!read_parameter_value(words, parameters.twojmax, keyword, error)) + { + return false; + } + has_twojmax = true; } else if (keyword == "rfac0") { - words >> parameters.rfac0; + if (!read_parameter_value(words, parameters.rfac0, keyword, error)) + { + return false; + } } else if (keyword == "rmin0") { - words >> parameters.rmin; + if (!read_parameter_value(words, parameters.rmin, keyword, error)) + { + return false; + } } else if (keyword == "bnormflag") { int value = 0; - words >> value; + if (!read_parameter_value(words, value, keyword, error)) + { + return false; + } parameters.bnorm_flag = value != 0; } else if (keyword == "switchflag") { int value = 0; - words >> value; + if (!read_parameter_value(words, value, keyword, error)) + { + return false; + } parameters.switch_flag = value != 0; } else if (keyword == "bzeroflag") { int value = 0; - words >> value; + if (!read_parameter_value(words, value, keyword, error)) + { + return false; + } parameters.bzero_flag = value != 0; } else if (keyword == "quadraticflag") { int value = 0; - words >> value; + if (!read_parameter_value(words, value, keyword, error)) + { + return false; + } parameters.quadratic_flag = value != 0; } else if (keyword == "wselfallflag") { int value = 0; - words >> value; + if (!read_parameter_value(words, value, keyword, error)) + { + return false; + } parameters.wselfall_flag = value != 0; } else if (keyword == "chemflag") { int value = 0; - words >> value; + if (!read_parameter_value(words, value, keyword, error)) + { + return false; + } parameters.chem_flag = value != 0; } } @@ -258,11 +301,6 @@ bool ModelData::load(const std::string& coefficient_file, error = "SNAP parameter file must define rcutfac and twojmax."; return false; } - if (parameters.chem_flag) - { - error = "Chemical SNAP channels are not implemented in this CPU stage."; - return false; - } double maximum_cutoff = 0.0; for (std::size_t i = 0; i < parameters.element_radii.size(); ++i) { diff --git a/source/source_md/snap/test/test_snap_calculator.cpp b/source/source_md/snap/test/test_snap_calculator.cpp index 498d6cd85eb..7ef14734e63 100644 --- a/source/source_md/snap/test/test_snap_calculator.cpp +++ b/source/source_md/snap/test/test_snap_calculator.cpp @@ -22,6 +22,50 @@ ModuleMD::SNAP::ModelData make_model() return model; } +ModuleMD::SNAP::ModelData make_multi_element_model() +{ + ModuleMD::SNAP::ModelData model; + model.parameters.rcut = 4.5; + model.parameters.rcutfac = 1.0; + model.parameters.rmin = 0.0; + model.parameters.rfac0 = 0.99363; + model.parameters.twojmax = 0; + model.parameters.bzero_flag = false; + model.parameters.elements.push_back("Si"); + model.parameters.elements.push_back("C"); + model.parameters.element_weights.push_back(1.0); + model.parameters.element_weights.push_back(0.8); + model.parameters.element_radii.push_back(2.25); + model.parameters.element_radii.push_back(1.7); + model.coefficients.push_back(std::vector{2.0, 3.0}); + model.coefficients.push_back(std::vector{5.0, 7.0}); + return model; +} + +ModuleMD::SNAP::ModelData make_chemical_model() +{ + ModuleMD::SNAP::ModelData model; + model.parameters.rcut = 4.5; + model.parameters.rcutfac = 1.0; + model.parameters.rmin = 0.0; + model.parameters.rfac0 = 0.99363; + model.parameters.twojmax = 0; + model.parameters.bnorm_flag = true; + model.parameters.chem_flag = true; + model.parameters.wselfall_flag = true; + model.parameters.elements.push_back("Si"); + model.parameters.elements.push_back("C"); + model.parameters.element_weights.push_back(1.0); + model.parameters.element_weights.push_back(0.8); + model.parameters.element_radii.push_back(2.25); + model.parameters.element_radii.push_back(1.7); + model.coefficients.push_back(std::vector(9, 0.0)); + model.coefficients.push_back(std::vector(9, 0.0)); + model.coefficients[0][1] = 2.0; + model.coefficients[1][1] = 3.0; + return model; +} + TEST(SnapCalculator, ComputesLinearAtomicEnergy) { const ModuleMD::SNAP::Calculator calculator(make_model()); @@ -35,6 +79,47 @@ TEST(SnapCalculator, ComputesLinearAtomicEnergy) EXPECT_DOUBLE_EQ(result.energy, 2.0 + 3.0 * result.descriptor[0]); } +TEST(SnapCalculator, SupportsMultipleCentralElements) +{ + const ModuleMD::SNAP::Calculator calculator(make_multi_element_model()); + const std::vector neighbors; + const ModuleMD::SNAP::EnergyResult silicon = calculator.compute(neighbors, 0); + const ModuleMD::SNAP::EnergyResult carbon = calculator.compute(neighbors, 1); + + EXPECT_DOUBLE_EQ(silicon.energy, 2.0 + 3.0 * silicon.descriptor[0]); + EXPECT_DOUBLE_EQ(carbon.energy, 5.0 + 7.0 * carbon.descriptor[0]); + EXPECT_NE(silicon.energy, carbon.energy); +} + +TEST(SnapCalculator, SupportsChemicalChannels) +{ + const ModuleMD::SNAP::Calculator calculator(make_chemical_model()); + ModuleMD::SNAP::Neighbor silicon; + silicon.x = 1.0; + silicon.cutoff_radius = 4.5; + silicon.element_index = 0; + ModuleMD::SNAP::Neighbor carbon = silicon; + carbon.y = 1.0; + carbon.element_index = 1; + const std::vector neighbors = {silicon, carbon}; + + const ModuleMD::SNAP::ForceResult analytic = calculator.compute_with_analytic_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult finite_difference + = calculator.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); + + EXPECT_EQ(analytic.energy.descriptor.size(), static_cast(8)); + EXPECT_NEAR(analytic.energy.energy, finite_difference.energy.energy, 1.0e-12); + for (int direction = 0; direction < 3; ++direction) + { + EXPECT_NEAR(analytic.center_force[static_cast(direction)], + finite_difference.center_force[static_cast(direction)], + 1.0e-5); + EXPECT_NEAR(analytic.neighbor_forces[0][static_cast(direction)], + finite_difference.neighbor_forces[0][static_cast(direction)], + 1.0e-5); + } +} + TEST(SnapCalculator, RejectsMismatchedCoefficientCount) { ModuleMD::SNAP::ModelData model = make_model(); diff --git a/source/source_md/snap/test/test_snap_model.cpp b/source/source_md/snap/test/test_snap_model.cpp index f20c83928b7..0d7a0873433 100644 --- a/source/source_md/snap/test/test_snap_model.cpp +++ b/source/source_md/snap/test/test_snap_model.cpp @@ -58,8 +58,8 @@ TEST(SnapModel, RejectsInvalidRadialRange) TEST(SnapModel, LoadsLammpsStyleCoefficientAndParameterFiles) { - const std::string coefficient_file = "/tmp/snap_coeff_test.txt"; - const std::string parameter_file = "/tmp/snap_param_test.txt"; + const std::string coefficient_file = testing::TempDir() + "snap_coeff_test.txt"; + const std::string parameter_file = testing::TempDir() + "snap_param_test.txt"; { std::ofstream output(coefficient_file.c_str()); output << "1 3\n"; @@ -90,4 +90,82 @@ TEST(SnapModel, LoadsLammpsStyleCoefficientAndParameterFiles) std::remove(parameter_file.c_str()); } +TEST(SnapModel, LoadsMultipleElementBlocks) +{ + const std::string coefficient_file = testing::TempDir() + "snap_coeff_multi_test.txt"; + const std::string parameter_file = testing::TempDir() + "snap_param_multi_test.txt"; + { + std::ofstream output(coefficient_file.c_str()); + output << "2 2\n"; + output << "Si 2.25 1.0\n"; + output << "-0.5\n1.25\n"; + output << "C 1.7 0.8\n"; + output << "-0.25\n2.5\n"; + } + { + std::ofstream output(parameter_file.c_str()); + output << "rcutfac 1.0\n"; + output << "twojmax 0\n"; + output << "rfac0 0.99363\n"; + output << "rmin0 0.0\n"; + output << "chemflag 0\n"; + } + + ModuleMD::SNAP::ModelData model; + std::string error; + const std::vector elements = {"Si", "C"}; + EXPECT_TRUE(model.load(coefficient_file, parameter_file, elements, error)); + EXPECT_TRUE(error.empty()); + ASSERT_EQ(model.coefficients.size(), static_cast(2)); + EXPECT_DOUBLE_EQ(model.parameters.element_weights[1], 0.8); + EXPECT_DOUBLE_EQ(model.parameters.element_radii[1], 1.7); + EXPECT_DOUBLE_EQ(model.coefficients[1][1], 2.5); + + std::remove(coefficient_file.c_str()); + std::remove(parameter_file.c_str()); +} + +TEST(SnapModel, LoadsChemicalCoefficientBlocks) +{ + const std::string coefficient_file = testing::TempDir() + "snap_coeff_chemical_test.txt"; + const std::string parameter_file = testing::TempDir() + "snap_param_chemical_test.txt"; + { + std::ofstream output(coefficient_file.c_str()); + output << "2 9\n"; + output << "Si 2.25 1.0\n"; + for (int i = 0; i < 9; ++i) + { + output << (i == 1 ? 1.0 : 0.0) << "\n"; + } + output << "C 1.7 0.8\n"; + for (int i = 0; i < 9; ++i) + { + output << (i == 1 ? 2.0 : 0.0) << "\n"; + } + } + { + std::ofstream output(parameter_file.c_str()); + output << "rcutfac 1.0\n"; + output << "twojmax 0\n"; + output << "rfac0 0.99363\n"; + output << "rmin0 0.0\n"; + output << "chemflag 1\n"; + output << "bnormflag 1\n"; + output << "wselfallflag 1\n"; + } + + ModuleMD::SNAP::ModelData model; + std::string error; + const std::vector elements = {"Si", "C"}; + EXPECT_TRUE(model.load(coefficient_file, parameter_file, elements, error)); + EXPECT_TRUE(error.empty()); + ASSERT_EQ(model.coefficients.size(), static_cast(2)); + EXPECT_TRUE(model.parameters.chem_flag); + EXPECT_EQ(model.coefficients[0].size(), static_cast(9)); + EXPECT_DOUBLE_EQ(model.coefficients[1][1], 2.0); + + std::remove(coefficient_file.c_str()); + std::remove(parameter_file.c_str()); +} + } // namespace diff --git a/tests/04_FF/102_SNAP_minimal/INPUT b/tests/04_FF/102_SNAP_minimal/INPUT new file mode 100644 index 00000000000..7b78253b090 --- /dev/null +++ b/tests/04_FF/102_SNAP_minimal/INPUT @@ -0,0 +1,12 @@ +INPUT_PARAMETERS +calculation md +suffix autotest +esolver_type snap +pot_file snapcoeff +snap_param_file snapparam +cal_force 1 +cal_stress 1 +md_nstep 1 +md_type nve +md_dt 1 +init_vel 0 diff --git a/tests/04_FF/102_SNAP_minimal/README b/tests/04_FF/102_SNAP_minimal/README new file mode 100644 index 00000000000..48dd6b6bb6e --- /dev/null +++ b/tests/04_FF/102_SNAP_minimal/README @@ -0,0 +1,5 @@ +CPU SNAP regression case with a two-atom Si periodic structure. + +The reference values are generated by ABACUS and checked by the existing +04_FF regression harness. The large cell keeps periodic image interactions +separate while exercising SNAP energy, force, and stress evaluation. diff --git a/tests/04_FF/102_SNAP_minimal/STRU b/tests/04_FF/102_SNAP_minimal/STRU new file mode 100644 index 00000000000..8e59e8a0b97 --- /dev/null +++ b/tests/04_FF/102_SNAP_minimal/STRU @@ -0,0 +1,19 @@ +ATOMIC_SPECIES +Si 28.0855 auto auto + +LATTICE_CONSTANT +1.0 + +LATTICE_VECTORS +20.0 0.0 0.0 +0.0 20.0 0.0 +0.0 0.0 20.0 + +ATOMIC_POSITIONS +Cartesian + +Si +0 +2 +0.0 0.0 0.0 m 1 1 1 +2.0 0.0 0.0 m 1 1 1 diff --git a/tests/04_FF/102_SNAP_minimal/result.ref b/tests/04_FF/102_SNAP_minimal/result.ref new file mode 100644 index 00000000000..c614edc058b --- /dev/null +++ b/tests/04_FF/102_SNAP_minimal/result.ref @@ -0,0 +1,5 @@ +etotref 12.868615 +etotperatomref 6.4343075000 +totalforceref 60.064486 +totalstressref 42.957208 +totaltimeref 35.66 diff --git a/tests/04_FF/102_SNAP_minimal/snapcoeff b/tests/04_FF/102_SNAP_minimal/snapcoeff new file mode 100644 index 00000000000..2766939f9b3 --- /dev/null +++ b/tests/04_FF/102_SNAP_minimal/snapcoeff @@ -0,0 +1,61 @@ +# DATE: 2020-01-31 UNITS: metal CONTRIBUTOR: Yunxing Zuo CITATION: Y. Zuo, C. Chen, X, Li, Z. Deng, Y. Chen, J. Behler, G. Csányi, A. V. Shapeev, A. P. Thompson, M. A. Wood, S. P. Ong, "Performance and Cost Assessment of Machine Learning Interatomic Potentials" J. Phys. Chem. A 124, 4, 731-745 (2020) +# Generated by Materials Virtual Lab + +1 56 +Si 0.5 1 +-5.663990890722773 +2.135204505942156e-05 +0.01812688733288438 +0.05890084411385875 +-0.016040522397783287 +0.2494122937439849 +0.030685603182186407 +0.07897074613855619 +0.03775626980109443 +0.08012875460906028 +0.11447594456727353 +0.08770261320757494 +-0.014534999402703207 +-0.016756593957058016 +0.011119293334051157 +0.015633833128521908 +0.026807206079160067 +0.04870622354746678 +-0.06492810262901873 +0.002910199026683352 +-0.019908133833638274 +-0.017872613445740447 +0.0031311465759044123 +0.011978920186307855 +0.0036899231853172246 +0.03006578350372085 +0.021354421560243725 +-0.03643908247119505 +-0.00831639295486291 +-0.04990225691971903 +-0.0010633320986013165 +-0.03193409548541607 +-0.003055748773152782 +0.002573793612554956 +0.0044391007289529515 +0.0325144360034856 +0.005840334419032887 +-0.004912536969652485 +-0.016370550877355387 +0.002140265199864603 +-0.027229855984721617 +-0.008278354893853326 +-0.006191386043061048 +0.0006411177578441998 +0.00552251715009933 +0.021112108349453373 +-0.0072983636775871275 +-0.002894532519792062 +-0.011272781710144501 +-0.008790720107990663 +-0.0069330757563178524 +0.0012142867357010229 +0.007119555811982486 +0.0010458619432982784 +0.006896454998006431 +-0.0034341539192112164 diff --git a/tests/04_FF/102_SNAP_minimal/snapparam b/tests/04_FF/102_SNAP_minimal/snapparam new file mode 100644 index 00000000000..f974e7016e1 --- /dev/null +++ b/tests/04_FF/102_SNAP_minimal/snapparam @@ -0,0 +1,9 @@ +# DATE: 2020-01-31 UNITS: metal CONTRIBUTOR: Yunxing Zuo CITATION: Y. Zuo, C. Chen, X, Li, Z. Deng, Y. Chen, J. Behler, G. Csányi, A. V. Shapeev, A. P. Thompson, M. A. Wood, S. P. Ong, "Performance and Cost Assessment of Machine Learning Interatomic Potentials" J. Phys. Chem. A 124, 4, 731-745 (2020) +# Generated by Materials Virtual Lab + +rcutfac 4.9 +twojmax 8 +rfac0 0.99363 +rmin0 0 +quadraticflag 0 +bzeroflag 0 diff --git a/tests/04_FF/CASES_CPU.txt b/tests/04_FF/CASES_CPU.txt index 886fac4f083..5beefe612c9 100644 --- a/tests/04_FF/CASES_CPU.txt +++ b/tests/04_FF/CASES_CPU.txt @@ -20,3 +20,4 @@ 20_LJ_dry_run #50_DP_Al #101_NEP_HfO2 +102_SNAP_minimal From 0137a83c5aa28fea28d36df48ce971ce2f6055df Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Thu, 29 Oct 2026 18:02:55 +0800 Subject: [PATCH 03/33] fix: avoid global dependency in SNAP factory --- source/source_esolver/esolver_factory.cpp | 3 +-- source/source_esolver/esolver_snap.cpp | 14 ++++++-------- source/source_esolver/esolver_snap.h | 6 +----- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/source/source_esolver/esolver_factory.cpp b/source/source_esolver/esolver_factory.cpp index 44ed98fb4f3..0c798613251 100644 --- a/source/source_esolver/esolver_factory.cpp +++ b/source/source_esolver/esolver_factory.cpp @@ -5,7 +5,6 @@ #include "esolver_dfpt_pw.h" #include "esolver_sdft_pw.h" #include "esolver_ks_pw_tddft.h" -#include "source_base/global_variable.h" #include "source_base/module_device/device.h" #include "source_hamilt/module_xc/general_exx_info.h" #include "source_io/module_parameter/parameter.h" @@ -398,7 +397,7 @@ ESolver* init_esolver(const Input_para& inp) } else if (esolver_type == "snap_pot") { - return new ESolver_SNAP(inp.mdp.pot_file, inp.mdp.snap_param_file, GlobalV::ofs_running); + return new ESolver_SNAP(inp.mdp.pot_file, inp.mdp.snap_param_file); } throw std::invalid_argument("esolver_type = " + std::string(esolver_type) + ". Wrong in " + std::string(__FILE__) + " line " + std::to_string(__LINE__)); diff --git a/source/source_esolver/esolver_snap.cpp b/source/source_esolver/esolver_snap.cpp index f3f3d979054..3b95469d34d 100644 --- a/source/source_esolver/esolver_snap.cpp +++ b/source/source_esolver/esolver_snap.cpp @@ -40,10 +40,8 @@ ModuleMD::SNAP::Neighbor make_neighbor(const NeighborAtom& center, } } -ESolver_SNAP::ESolver_SNAP(const std::string& coefficient_file, - const std::string& parameter_file, - std::ofstream& running_log) - : coefficient_file_(coefficient_file), parameter_file_(parameter_file), running_log_(running_log) +ESolver_SNAP::ESolver_SNAP(const std::string& coefficient_file, const std::string& parameter_file) + : coefficient_file_(coefficient_file), parameter_file_(parameter_file) { classname = "ESolver_SNAP"; } @@ -254,7 +252,7 @@ void ESolver_SNAP::cal_force(BaseCell& cell, ModuleBase::matrix& force) return; } force = snap_force_; - ModuleIO::print_force(running_log_, + ModuleIO::print_force(GlobalV::ofs_running, static_cast(cell), "TOTAL-FORCE (eV/Angstrom)", force, @@ -267,7 +265,7 @@ void ESolver_SNAP::cal_stress(BaseCell& cell, ModuleBase::matrix& stress) if (cell.kind() == BaseCell::Kind::unitcell) { - ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, running_log_); + ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); } else { @@ -275,7 +273,7 @@ void ESolver_SNAP::cal_stress(BaseCell& cell, ModuleBase::matrix& stress) if (static_cast(cell).mpi_rank() == 0) #endif { - ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, running_log_); + ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); } } @@ -290,7 +288,7 @@ void ESolver_SNAP::cal_stress(BaseCell& cell, ModuleBase::matrix& stress) void ESolver_SNAP::after_all_runners(BaseCell& cell) { static_cast(cell); - running_log_ << "\n !FINAL_ETOT_IS " << snap_potential_ * ModuleBase::Ry_to_eV << " eV\n"; + GlobalV::ofs_running << "\n !FINAL_ETOT_IS " << snap_potential_ * ModuleBase::Ry_to_eV << " eV\n"; } } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_snap.h b/source/source_esolver/esolver_snap.h index 8dfeacaf0b6..c4c7aba2cdf 100644 --- a/source/source_esolver/esolver_snap.h +++ b/source/source_esolver/esolver_snap.h @@ -4,7 +4,6 @@ #include "esolver.h" #include "source_md/snap/snap_calculator.h" -#include #include #include #include @@ -15,9 +14,7 @@ namespace ModuleESolver class ESolver_SNAP : public ESolver { public: - ESolver_SNAP(const std::string& coefficient_file, - const std::string& parameter_file, - std::ofstream& running_log); + ESolver_SNAP(const std::string& coefficient_file, const std::string& parameter_file); void before_all_runners(BaseCell& cell, const Input_para& inp) override; void runner(BaseCell& cell, int istep) override; @@ -31,7 +28,6 @@ class ESolver_SNAP : public ESolver std::string coefficient_file_; std::string parameter_file_; - std::ofstream& running_log_; ModuleMD::SNAP::ModelData model_; std::unique_ptr calculator_; double snap_potential_ = 0.0; From c81603d454bb0b2e6a03371fc7b1311dd2f418e4 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Thu, 29 Oct 2026 18:10:00 +0800 Subject: [PATCH 04/33] fix: keep SNAP factory dependency budget neutral --- source/source_esolver/esolver_factory.cpp | 10 +++++----- source/source_esolver/esolver_snap.cpp | 14 ++++++++------ source/source_esolver/esolver_snap.h | 6 +++++- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/source/source_esolver/esolver_factory.cpp b/source/source_esolver/esolver_factory.cpp index 0c798613251..d69af4ac73a 100644 --- a/source/source_esolver/esolver_factory.cpp +++ b/source/source_esolver/esolver_factory.cpp @@ -5,6 +5,7 @@ #include "esolver_dfpt_pw.h" #include "esolver_sdft_pw.h" #include "esolver_ks_pw_tddft.h" +#include "source_base/global_variable.h" #include "source_base/module_device/device.h" #include "source_hamilt/module_xc/general_exx_info.h" #include "source_io/module_parameter/parameter.h" @@ -135,7 +136,6 @@ std::string determine_type(const Input_para& inp) } } base_device::information::output_device_info(std::cout, inp.device); - base_device::information::output_device_info(GlobalV::ofs_running, inp.device); /***auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast>(end_time - start_time); std::cout << "hipGetDeviceInfo took " << duration.count() << " seconds" << std::endl;***/ @@ -147,7 +147,7 @@ ESolver* init_esolver(const Input_para& inp) { // determine type of esolver based on INPUT information const std::string esolver_type = determine_type(inp); - const bool gamma_only = PARAM.globalv.gamma_only_local; + const bool gamma_only = inp.gamma_only; #ifdef __LCAO const LRRuntime lr_runtime{GlobalV::ofs_running, GlobalV::ofs_warning, GlobalV::MY_RANK}; #endif @@ -389,15 +389,15 @@ ESolver* init_esolver(const Input_para& inp) } else if (esolver_type == "dp_pot") { - return new ESolver_DP(PARAM.mdp.pot_file); + return new ESolver_DP(inp.mdp.pot_file); } else if (esolver_type == "nep_pot") { - return new ESolver_NEP(PARAM.mdp.pot_file); + return new ESolver_NEP(inp.mdp.pot_file); } else if (esolver_type == "snap_pot") { - return new ESolver_SNAP(inp.mdp.pot_file, inp.mdp.snap_param_file); + return new ESolver_SNAP(inp.mdp.pot_file, inp.mdp.snap_param_file, GlobalV::ofs_running); } throw std::invalid_argument("esolver_type = " + std::string(esolver_type) + ". Wrong in " + std::string(__FILE__) + " line " + std::to_string(__LINE__)); diff --git a/source/source_esolver/esolver_snap.cpp b/source/source_esolver/esolver_snap.cpp index 3b95469d34d..f3f3d979054 100644 --- a/source/source_esolver/esolver_snap.cpp +++ b/source/source_esolver/esolver_snap.cpp @@ -40,8 +40,10 @@ ModuleMD::SNAP::Neighbor make_neighbor(const NeighborAtom& center, } } -ESolver_SNAP::ESolver_SNAP(const std::string& coefficient_file, const std::string& parameter_file) - : coefficient_file_(coefficient_file), parameter_file_(parameter_file) +ESolver_SNAP::ESolver_SNAP(const std::string& coefficient_file, + const std::string& parameter_file, + std::ofstream& running_log) + : coefficient_file_(coefficient_file), parameter_file_(parameter_file), running_log_(running_log) { classname = "ESolver_SNAP"; } @@ -252,7 +254,7 @@ void ESolver_SNAP::cal_force(BaseCell& cell, ModuleBase::matrix& force) return; } force = snap_force_; - ModuleIO::print_force(GlobalV::ofs_running, + ModuleIO::print_force(running_log_, static_cast(cell), "TOTAL-FORCE (eV/Angstrom)", force, @@ -265,7 +267,7 @@ void ESolver_SNAP::cal_stress(BaseCell& cell, ModuleBase::matrix& stress) if (cell.kind() == BaseCell::Kind::unitcell) { - ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, running_log_); } else { @@ -273,7 +275,7 @@ void ESolver_SNAP::cal_stress(BaseCell& cell, ModuleBase::matrix& stress) if (static_cast(cell).mpi_rank() == 0) #endif { - ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, running_log_); } } @@ -288,7 +290,7 @@ void ESolver_SNAP::cal_stress(BaseCell& cell, ModuleBase::matrix& stress) void ESolver_SNAP::after_all_runners(BaseCell& cell) { static_cast(cell); - GlobalV::ofs_running << "\n !FINAL_ETOT_IS " << snap_potential_ * ModuleBase::Ry_to_eV << " eV\n"; + running_log_ << "\n !FINAL_ETOT_IS " << snap_potential_ * ModuleBase::Ry_to_eV << " eV\n"; } } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_snap.h b/source/source_esolver/esolver_snap.h index c4c7aba2cdf..8dfeacaf0b6 100644 --- a/source/source_esolver/esolver_snap.h +++ b/source/source_esolver/esolver_snap.h @@ -4,6 +4,7 @@ #include "esolver.h" #include "source_md/snap/snap_calculator.h" +#include #include #include #include @@ -14,7 +15,9 @@ namespace ModuleESolver class ESolver_SNAP : public ESolver { public: - ESolver_SNAP(const std::string& coefficient_file, const std::string& parameter_file); + ESolver_SNAP(const std::string& coefficient_file, + const std::string& parameter_file, + std::ofstream& running_log); void before_all_runners(BaseCell& cell, const Input_para& inp) override; void runner(BaseCell& cell, int istep) override; @@ -28,6 +31,7 @@ class ESolver_SNAP : public ESolver std::string coefficient_file_; std::string parameter_file_; + std::ofstream& running_log_; ModuleMD::SNAP::ModelData model_; std::unique_ptr calculator_; double snap_potential_ = 0.0; From f55e7ee7acc2c6cc293feb92159095d653acf897 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Thu, 29 Oct 2026 20:09:22 +0800 Subject: [PATCH 05/33] refactor: align SNAP module and file naming --- source/Makefile.Objects | 10 +++++----- source/source_esolver/esolver_snap.h | 2 +- source/source_io/module_parameter/md_parameter.h | 2 +- .../source_io/module_parameter/read_input_item_md.cpp | 2 +- source/source_md/CMakeLists.txt | 2 +- source/source_md/{snap => module_snap}/CMakeLists.txt | 2 +- .../{snap => module_snap}/snap_calculator.cpp | 0 .../source_md/{snap => module_snap}/snap_calculator.h | 0 .../{snap => module_snap}/snap_clebsch_gordan.cpp | 0 .../{snap => module_snap}/snap_clebsch_gordan.h | 0 .../{snap => module_snap}/snap_descriptor.cpp | 0 .../source_md/{snap => module_snap}/snap_descriptor.h | 0 source/source_md/{snap => module_snap}/snap_model.cpp | 0 source/source_md/{snap => module_snap}/snap_model.h | 0 .../{snap/test => module_snap/unittest}/CMakeLists.txt | 0 .../unittest}/test_snap_calculator.cpp | 0 .../unittest}/test_snap_clebsch_gordan.cpp | 0 .../unittest}/test_snap_descriptor.cpp | 0 .../test => module_snap/unittest}/test_snap_model.cpp | 0 tests/04_FF/102_SNAP_minimal/INPUT | 4 ++-- tests/04_FF/102_SNAP_minimal/README | 3 +++ tests/04_FF/102_SNAP_minimal/{snapcoeff => snap.coeff} | 0 tests/04_FF/102_SNAP_minimal/{snapparam => snap.param} | 0 23 files changed, 15 insertions(+), 12 deletions(-) rename source/source_md/{snap => module_snap}/CMakeLists.txt (84%) rename source/source_md/{snap => module_snap}/snap_calculator.cpp (100%) rename source/source_md/{snap => module_snap}/snap_calculator.h (100%) rename source/source_md/{snap => module_snap}/snap_clebsch_gordan.cpp (100%) rename source/source_md/{snap => module_snap}/snap_clebsch_gordan.h (100%) rename source/source_md/{snap => module_snap}/snap_descriptor.cpp (100%) rename source/source_md/{snap => module_snap}/snap_descriptor.h (100%) rename source/source_md/{snap => module_snap}/snap_model.cpp (100%) rename source/source_md/{snap => module_snap}/snap_model.h (100%) rename source/source_md/{snap/test => module_snap/unittest}/CMakeLists.txt (100%) rename source/source_md/{snap/test => module_snap/unittest}/test_snap_calculator.cpp (100%) rename source/source_md/{snap/test => module_snap/unittest}/test_snap_clebsch_gordan.cpp (100%) rename source/source_md/{snap/test => module_snap/unittest}/test_snap_descriptor.cpp (100%) rename source/source_md/{snap/test => module_snap/unittest}/test_snap_model.cpp (100%) rename tests/04_FF/102_SNAP_minimal/{snapcoeff => snap.coeff} (100%) rename tests/04_FF/102_SNAP_minimal/{snapparam => snap.param} (100%) diff --git a/source/Makefile.Objects b/source/Makefile.Objects index 12305919666..d3867979f01 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -32,7 +32,7 @@ VPATH=./src_global:\ ./source_base/module_out:\ ./source_md:\ ./source_md/module_plumed:\ -./source_md/snap:\ +./source_md/module_snap:\ ./source_basis/module_pw:\ ./source_base/module_fft:\ ./source_esolver:\ @@ -538,10 +538,10 @@ OBJS_MD=fire.o\ nhchain.o\ plumed_interface.o\ run_md.o\ - snap/snap_calculator.o\ - snap/snap_descriptor.o\ - snap/snap_model.o\ - snap/snap_clebsch_gordan.o\ + module_snap/snap_calculator.o\ + module_snap/snap_descriptor.o\ + module_snap/snap_model.o\ + module_snap/snap_clebsch_gordan.o\ verlet.o\ OBJS_NEIGHBOR=sltk_atom.o\ diff --git a/source/source_esolver/esolver_snap.h b/source/source_esolver/esolver_snap.h index 8dfeacaf0b6..cad1b79af4a 100644 --- a/source/source_esolver/esolver_snap.h +++ b/source/source_esolver/esolver_snap.h @@ -2,7 +2,7 @@ #define ESOLVER_SNAP_H #include "esolver.h" -#include "source_md/snap/snap_calculator.h" +#include "source_md/module_snap/snap_calculator.h" #include #include diff --git a/source/source_io/module_parameter/md_parameter.h b/source/source_io/module_parameter/md_parameter.h index 53fc63f2411..cdc601c8502 100644 --- a/source/source_io/module_parameter/md_parameter.h +++ b/source/source_io/module_parameter/md_parameter.h @@ -31,7 +31,7 @@ struct MD_para std::vector lj_epsilon = {}; ///< the value of epsilon for LJ potential (eV) std::vector lj_sigma = {}; ///< the value of sigma for LJ potential (\AA) std::string pot_file = "graph.pb"; ///< the filename of potential files for CMD such as DP - std::string snap_param_file = "snapparam"; ///< SNAP parameter file + std::string snap_param_file = "snap.param"; ///< SNAP parameter file double dp_rescaling = 1.0; ///< rescaling factor for DP model. Energy, force and stress will be multiplied by this factor. std::vector dp_fparam = {}; ///< The frame parameter for dp potential. The array can be of size : diff --git a/source/source_io/module_parameter/read_input_item_md.cpp b/source/source_io/module_parameter/read_input_item_md.cpp index 45e7d4908af..2602e1c421e 100644 --- a/source/source_io/module_parameter/read_input_item_md.cpp +++ b/source/source_io/module_parameter/read_input_item_md.cpp @@ -558,7 +558,7 @@ Note: It is a system-dependent empirical parameter. An improper choice might lea item.category = "Molecular dynamics"; item.type = "String"; item.description = "The SNAP parameter file used with pot_file as the SNAP coefficient file."; - item.default_value = "snapparam"; + item.default_value = "snap.param"; item.unit = ""; item.set_availability("esolver_type==snap"); read_sync_string(input.mdp.snap_param_file); diff --git a/source/source_md/CMakeLists.txt b/source/source_md/CMakeLists.txt index 7b23870b969..b71246d8370 100644 --- a/source/source_md/CMakeLists.txt +++ b/source/source_md/CMakeLists.txt @@ -9,7 +9,7 @@ add_library( run_md.cpp verlet.cpp) -add_subdirectory(snap) +add_subdirectory(module_snap) if(ENABLE_COVERAGE) add_coverage(md) diff --git a/source/source_md/snap/CMakeLists.txt b/source/source_md/module_snap/CMakeLists.txt similarity index 84% rename from source/source_md/snap/CMakeLists.txt rename to source/source_md/module_snap/CMakeLists.txt index 2ac1c97479e..9048598d617 100644 --- a/source/source_md/snap/CMakeLists.txt +++ b/source/source_md/module_snap/CMakeLists.txt @@ -8,5 +8,5 @@ target_sources( ) if(BUILD_TESTING) - add_subdirectory(test) + add_subdirectory(unittest) endif() diff --git a/source/source_md/snap/snap_calculator.cpp b/source/source_md/module_snap/snap_calculator.cpp similarity index 100% rename from source/source_md/snap/snap_calculator.cpp rename to source/source_md/module_snap/snap_calculator.cpp diff --git a/source/source_md/snap/snap_calculator.h b/source/source_md/module_snap/snap_calculator.h similarity index 100% rename from source/source_md/snap/snap_calculator.h rename to source/source_md/module_snap/snap_calculator.h diff --git a/source/source_md/snap/snap_clebsch_gordan.cpp b/source/source_md/module_snap/snap_clebsch_gordan.cpp similarity index 100% rename from source/source_md/snap/snap_clebsch_gordan.cpp rename to source/source_md/module_snap/snap_clebsch_gordan.cpp diff --git a/source/source_md/snap/snap_clebsch_gordan.h b/source/source_md/module_snap/snap_clebsch_gordan.h similarity index 100% rename from source/source_md/snap/snap_clebsch_gordan.h rename to source/source_md/module_snap/snap_clebsch_gordan.h diff --git a/source/source_md/snap/snap_descriptor.cpp b/source/source_md/module_snap/snap_descriptor.cpp similarity index 100% rename from source/source_md/snap/snap_descriptor.cpp rename to source/source_md/module_snap/snap_descriptor.cpp diff --git a/source/source_md/snap/snap_descriptor.h b/source/source_md/module_snap/snap_descriptor.h similarity index 100% rename from source/source_md/snap/snap_descriptor.h rename to source/source_md/module_snap/snap_descriptor.h diff --git a/source/source_md/snap/snap_model.cpp b/source/source_md/module_snap/snap_model.cpp similarity index 100% rename from source/source_md/snap/snap_model.cpp rename to source/source_md/module_snap/snap_model.cpp diff --git a/source/source_md/snap/snap_model.h b/source/source_md/module_snap/snap_model.h similarity index 100% rename from source/source_md/snap/snap_model.h rename to source/source_md/module_snap/snap_model.h diff --git a/source/source_md/snap/test/CMakeLists.txt b/source/source_md/module_snap/unittest/CMakeLists.txt similarity index 100% rename from source/source_md/snap/test/CMakeLists.txt rename to source/source_md/module_snap/unittest/CMakeLists.txt diff --git a/source/source_md/snap/test/test_snap_calculator.cpp b/source/source_md/module_snap/unittest/test_snap_calculator.cpp similarity index 100% rename from source/source_md/snap/test/test_snap_calculator.cpp rename to source/source_md/module_snap/unittest/test_snap_calculator.cpp diff --git a/source/source_md/snap/test/test_snap_clebsch_gordan.cpp b/source/source_md/module_snap/unittest/test_snap_clebsch_gordan.cpp similarity index 100% rename from source/source_md/snap/test/test_snap_clebsch_gordan.cpp rename to source/source_md/module_snap/unittest/test_snap_clebsch_gordan.cpp diff --git a/source/source_md/snap/test/test_snap_descriptor.cpp b/source/source_md/module_snap/unittest/test_snap_descriptor.cpp similarity index 100% rename from source/source_md/snap/test/test_snap_descriptor.cpp rename to source/source_md/module_snap/unittest/test_snap_descriptor.cpp diff --git a/source/source_md/snap/test/test_snap_model.cpp b/source/source_md/module_snap/unittest/test_snap_model.cpp similarity index 100% rename from source/source_md/snap/test/test_snap_model.cpp rename to source/source_md/module_snap/unittest/test_snap_model.cpp diff --git a/tests/04_FF/102_SNAP_minimal/INPUT b/tests/04_FF/102_SNAP_minimal/INPUT index 7b78253b090..0ed0eb5b3ab 100644 --- a/tests/04_FF/102_SNAP_minimal/INPUT +++ b/tests/04_FF/102_SNAP_minimal/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file snapcoeff -snap_param_file snapparam +pot_file snap.coeff +snap_param_file snap.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/102_SNAP_minimal/README b/tests/04_FF/102_SNAP_minimal/README index 48dd6b6bb6e..256d7c340c2 100644 --- a/tests/04_FF/102_SNAP_minimal/README +++ b/tests/04_FF/102_SNAP_minimal/README @@ -1,5 +1,8 @@ CPU SNAP regression case with a two-atom Si periodic structure. +The example uses `snap.coeff` for the SNAP coefficients and `snap.param` for +the SNAP parameters. + The reference values are generated by ABACUS and checked by the existing 04_FF regression harness. The large cell keeps periodic image interactions separate while exercising SNAP energy, force, and stress evaluation. diff --git a/tests/04_FF/102_SNAP_minimal/snapcoeff b/tests/04_FF/102_SNAP_minimal/snap.coeff similarity index 100% rename from tests/04_FF/102_SNAP_minimal/snapcoeff rename to tests/04_FF/102_SNAP_minimal/snap.coeff diff --git a/tests/04_FF/102_SNAP_minimal/snapparam b/tests/04_FF/102_SNAP_minimal/snap.param similarity index 100% rename from tests/04_FF/102_SNAP_minimal/snapparam rename to tests/04_FF/102_SNAP_minimal/snap.param From 70178c542f9d2504542387bde623e675aa86de88 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Thu, 29 Oct 2026 20:34:51 +0800 Subject: [PATCH 06/33] test: use ABACUS-generated SNAP fixture --- tests/04_FF/102_SNAP_minimal/README | 5 + tests/04_FF/102_SNAP_minimal/result.ref | 8 +- tests/04_FF/102_SNAP_minimal/snap.coeff | 117 ++++++++++++------------ tests/04_FF/102_SNAP_minimal/snap.param | 5 +- 4 files changed, 71 insertions(+), 64 deletions(-) diff --git a/tests/04_FF/102_SNAP_minimal/README b/tests/04_FF/102_SNAP_minimal/README index 256d7c340c2..26ce3c2fdea 100644 --- a/tests/04_FF/102_SNAP_minimal/README +++ b/tests/04_FF/102_SNAP_minimal/README @@ -3,6 +3,11 @@ CPU SNAP regression case with a two-atom Si periodic structure. The example uses `snap.coeff` for the SNAP coefficients and `snap.param` for the SNAP parameters. +The coefficient and parameter files are deterministic ABACUS-generated test +fixtures. They are intended only to exercise SNAP parsing, energy, force, and +stress evaluation; they are not transferable or physically validated Si +potentials. + The reference values are generated by ABACUS and checked by the existing 04_FF regression harness. The large cell keeps periodic image interactions separate while exercising SNAP energy, force, and stress evaluation. diff --git a/tests/04_FF/102_SNAP_minimal/result.ref b/tests/04_FF/102_SNAP_minimal/result.ref index c614edc058b..3a0762311ec 100644 --- a/tests/04_FF/102_SNAP_minimal/result.ref +++ b/tests/04_FF/102_SNAP_minimal/result.ref @@ -1,5 +1,5 @@ -etotref 12.868615 -etotperatomref 6.4343075000 -totalforceref 60.064486 -totalstressref 42.957208 +etotref -0.621502 +etotperatomref -0.3107510650 +totalforceref 5.604078 +totalstressref -4.007952 totaltimeref 35.66 diff --git a/tests/04_FF/102_SNAP_minimal/snap.coeff b/tests/04_FF/102_SNAP_minimal/snap.coeff index 2766939f9b3..fc13f2f7b43 100644 --- a/tests/04_FF/102_SNAP_minimal/snap.coeff +++ b/tests/04_FF/102_SNAP_minimal/snap.coeff @@ -1,61 +1,62 @@ -# DATE: 2020-01-31 UNITS: metal CONTRIBUTOR: Yunxing Zuo CITATION: Y. Zuo, C. Chen, X, Li, Z. Deng, Y. Chen, J. Behler, G. Csányi, A. V. Shapeev, A. P. Thompson, M. A. Wood, S. P. Ong, "Performance and Cost Assessment of Machine Learning Interatomic Potentials" J. Phys. Chem. A 124, 4, 731-745 (2020) -# Generated by Materials Virtual Lab +# ABACUS-generated SNAP regression fixture +# This deterministic coefficient set is created for software testing only. +# It is not a transferable or physically validated material potential. 1 56 Si 0.5 1 --5.663990890722773 -2.135204505942156e-05 -0.01812688733288438 -0.05890084411385875 --0.016040522397783287 -0.2494122937439849 -0.030685603182186407 -0.07897074613855619 -0.03775626980109443 -0.08012875460906028 -0.11447594456727353 -0.08770261320757494 --0.014534999402703207 --0.016756593957058016 -0.011119293334051157 -0.015633833128521908 -0.026807206079160067 -0.04870622354746678 --0.06492810262901873 -0.002910199026683352 --0.019908133833638274 --0.017872613445740447 -0.0031311465759044123 -0.011978920186307855 -0.0036899231853172246 -0.03006578350372085 -0.021354421560243725 --0.03643908247119505 --0.00831639295486291 --0.04990225691971903 --0.0010633320986013165 --0.03193409548541607 --0.003055748773152782 -0.002573793612554956 -0.0044391007289529515 -0.0325144360034856 -0.005840334419032887 --0.004912536969652485 --0.016370550877355387 -0.002140265199864603 --0.027229855984721617 --0.008278354893853326 --0.006191386043061048 -0.0006411177578441998 -0.00552251715009933 -0.021112108349453373 --0.0072983636775871275 --0.002894532519792062 --0.011272781710144501 --0.008790720107990663 --0.0069330757563178524 -0.0012142867357010229 -0.007119555811982486 -0.0010458619432982784 -0.006896454998006431 --0.0034341539192112164 +0.125000000000 +-0.002000000000 +0.003000000000 +-0.004000000000 +0.005000000000 +-0.006000000000 +0.007000000000 +-0.008000000000 +0.009000000000 +-0.010000000000 +0.011000000000 +-0.012000000000 +0.013000000000 +-0.014000000000 +0.015000000000 +-0.016000000000 +0.017000000000 +-0.018000000000 +0.019000000000 +-0.020000000000 +0.021000000000 +-0.022000000000 +0.023000000000 +-0.024000000000 +0.025000000000 +-0.026000000000 +0.027000000000 +-0.028000000000 +0.029000000000 +-0.030000000000 +0.031000000000 +-0.032000000000 +0.033000000000 +-0.034000000000 +0.035000000000 +-0.036000000000 +0.037000000000 +-0.038000000000 +0.039000000000 +-0.040000000000 +0.041000000000 +-0.042000000000 +0.043000000000 +-0.044000000000 +0.045000000000 +-0.046000000000 +0.047000000000 +-0.048000000000 +0.049000000000 +-0.050000000000 +0.051000000000 +-0.052000000000 +0.053000000000 +-0.054000000000 +0.055000000000 +-0.056000000000 diff --git a/tests/04_FF/102_SNAP_minimal/snap.param b/tests/04_FF/102_SNAP_minimal/snap.param index f974e7016e1..23e0d83d38b 100644 --- a/tests/04_FF/102_SNAP_minimal/snap.param +++ b/tests/04_FF/102_SNAP_minimal/snap.param @@ -1,5 +1,6 @@ -# DATE: 2020-01-31 UNITS: metal CONTRIBUTOR: Yunxing Zuo CITATION: Y. Zuo, C. Chen, X, Li, Z. Deng, Y. Chen, J. Behler, G. Csányi, A. V. Shapeev, A. P. Thompson, M. A. Wood, S. P. Ong, "Performance and Cost Assessment of Machine Learning Interatomic Potentials" J. Phys. Chem. A 124, 4, 731-745 (2020) -# Generated by Materials Virtual Lab +# ABACUS-generated SNAP regression fixture +# This deterministic parameter set is created for software testing only. +# It is not a transferable or physically validated material potential. rcutfac 4.9 twojmax 8 From 64e53b955e54f3371b12a2c47aaf7b567edcf1b1 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Thu, 29 Oct 2026 20:52:13 +0800 Subject: [PATCH 07/33] refactor: split SNAP descriptor derivatives --- source/Makefile.Objects | 1 + source/source_md/module_snap/CMakeLists.txt | 1 + .../source_md/module_snap/snap_descriptor.cpp | 185 ---------------- .../snap_descriptor_derivative.cpp | 199 ++++++++++++++++++ .../module_snap/unittest/CMakeLists.txt | 4 +- 5 files changed, 203 insertions(+), 187 deletions(-) create mode 100644 source/source_md/module_snap/snap_descriptor_derivative.cpp diff --git a/source/Makefile.Objects b/source/Makefile.Objects index d3867979f01..d61284f431c 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -540,6 +540,7 @@ OBJS_MD=fire.o\ run_md.o\ module_snap/snap_calculator.o\ module_snap/snap_descriptor.o\ + module_snap/snap_descriptor_derivative.o\ module_snap/snap_model.o\ module_snap/snap_clebsch_gordan.o\ verlet.o\ diff --git a/source/source_md/module_snap/CMakeLists.txt b/source/source_md/module_snap/CMakeLists.txt index 9048598d617..3a3a8f7ec7e 100644 --- a/source/source_md/module_snap/CMakeLists.txt +++ b/source/source_md/module_snap/CMakeLists.txt @@ -3,6 +3,7 @@ target_sources( PRIVATE snap_calculator.cpp snap_descriptor.cpp + snap_descriptor_derivative.cpp snap_model.cpp snap_clebsch_gordan.cpp ) diff --git a/source/source_md/module_snap/snap_descriptor.cpp b/source/source_md/module_snap/snap_descriptor.cpp index daf9f6f95e5..bc2642ec827 100644 --- a/source/source_md/module_snap/snap_descriptor.cpp +++ b/source/source_md/module_snap/snap_descriptor.cpp @@ -11,107 +11,6 @@ namespace ModuleMD namespace SNAP { -namespace -{ -struct Dual -{ - double value; - double derivative; - - Dual(const double value_in = 0.0, const double derivative_in = 0.0) - : value(value_in), derivative(derivative_in) - { - } -}; - -Dual operator+(const Dual& left, const Dual& right) -{ - return Dual(left.value + right.value, left.derivative + right.derivative); -} - -Dual operator-(const Dual& left, const Dual& right) -{ - return Dual(left.value - right.value, left.derivative - right.derivative); -} - -Dual operator-(const Dual& value) -{ - return Dual(-value.value, -value.derivative); -} - -Dual operator*(const Dual& left, const Dual& right) -{ - return Dual(left.value * right.value, - left.derivative * right.value + left.value * right.derivative); -} - -Dual operator/(const Dual& left, const Dual& right) -{ - const double inverse = 1.0 / right.value; - return Dual(left.value * inverse, - (left.derivative * right.value - left.value * right.derivative) * inverse * inverse); -} - -Dual operator+(const Dual& left, const double right) -{ - return left + Dual(right); -} - -Dual operator-(const Dual& left, const double right) -{ - return left - Dual(right); -} - -Dual operator*(const Dual& left, const double right) -{ - return left * Dual(right); -} - -Dual operator*(const double left, const Dual& right) -{ - return Dual(left) * right; -} - -Dual operator/(const Dual& left, const double right) -{ - return left / Dual(right); -} - -Dual operator/(const double left, const Dual& right) -{ - return Dual(left) / right; -} - -Dual& operator*=(Dual& left, const Dual& right) -{ - left = left * right; - return left; -} - -Dual& operator+=(Dual& left, const Dual& right) -{ - left = left + right; - return left; -} - -Dual dual_sqrt(const Dual& value) -{ - const double root = std::sqrt(value.value); - return Dual(root, value.derivative / (2.0 * root)); -} - -Dual dual_cos(const Dual& value) -{ - return Dual(std::cos(value.value), -std::sin(value.value) * value.derivative); -} - -Dual dual_tan(const Dual& value) -{ - const double cosine = std::cos(value.value); - return Dual(std::tan(value.value), value.derivative / (cosine * cosine)); -} -} - DescriptorEvaluator::DescriptorEvaluator(const ModelParameters& parameters) : parameters_(parameters), cg_table_(parameters.twojmax), u_size_(0) { @@ -237,90 +136,6 @@ std::vector > DescriptorEvaluator::compute_u(const Neighbor return result; } -UWithDerivative DescriptorEvaluator::compute_u_with_derivative(const Neighbor& neighbor, const int direction) const -{ - if (direction < 0 || direction > 2) - { - throw std::invalid_argument("SNAP derivative direction must be 0, 1, or 2."); - } - const Dual x(neighbor.x, direction == 0 ? 1.0 : 0.0); - const Dual y(neighbor.y, direction == 1 ? 1.0 : 0.0); - const Dual z(neighbor.z, direction == 2 ? 1.0 : 0.0); - const Dual rsq = x * x + y * y + z * z; - const Dual distance = dual_sqrt(rsq); - const double cutoff_radius = neighbor.cutoff_radius > 0.0 ? neighbor.cutoff_radius : parameters_.rcut; - - UWithDerivative result; - result.values.assign(u_size_, std::complex(0.0, 0.0)); - result.derivatives.assign(u_size_, std::complex(0.0, 0.0)); - if (distance.value <= 1.0e-14 || distance.value >= cutoff_radius) - { - return result; - } - - Dual scale; - if (!parameters_.switch_flag) - { - scale = Dual(1.0); - } - else if (distance.value <= parameters_.rmin) - { - scale = Dual(1.0); - } - else - { - const Dual angle = (distance - parameters_.rmin) * ModuleBase::PI - / (cutoff_radius - parameters_.rmin); - scale = 0.5 * (dual_cos(angle) + 1.0); - } - scale = scale * neighbor.weight; - - const Dual theta0 = (distance - parameters_.rmin) * parameters_.rfac0 * ModuleBase::PI - / (cutoff_radius - parameters_.rmin); - const Dual z0 = distance / dual_tan(theta0); - const Dual r0inv = 1.0 / dual_sqrt(rsq + z0 * z0); - const Dual ar = r0inv * z0; - const Dual ai = -r0inv * z; - const Dual br = r0inv * y; - const Dual bi = -r0inv * x; - std::vector > raw(u_size_, std::complex(Dual(0.0), Dual(0.0))); - raw[0] = std::complex(Dual(1.0), Dual(0.0)); - const int dimension = parameters_.twojmax + 1; - for (int j = 1; j <= parameters_.twojmax; ++j) - { - for (int mb = 0; 2 * mb <= j; ++mb) - { - raw[u_index(j, 0, mb)] = std::complex(Dual(0.0), Dual(0.0)); - for (int ma = 0; ma < j; ++ma) - { - const std::size_t current = u_index(j, ma, mb); - const std::size_t previous = u_index(j - 1, ma, mb); - const double first_root = rootpq_[static_cast((j - ma) * dimension + (j - mb))]; - const double second_root = rootpq_[static_cast((ma + 1) * dimension + (j - mb))]; - raw[current] += Dual(first_root) * std::complex(ar, -ai) * raw[previous]; - raw[current + 1] = Dual(-second_root) * std::complex(br, -bi) * raw[previous]; - } - } - for (int mb = 0; 2 * mb <= j; ++mb) - { - for (int ma = 0; ma <= j; ++ma) - { - const std::size_t left = u_index(j, ma, mb); - const std::size_t right = u_index(j, j - ma, j - mb); - const double sign = ((ma - mb) % 2 == 0) ? 1.0 : -1.0; - raw[right] = Dual(sign) * std::conj(raw[left]); - } - } - } - for (std::size_t i = 0; i < raw.size(); ++i) - { - const std::complex value = scale * raw[i]; - result.values[i] = std::complex(value.real().value, value.imag().value); - result.derivatives[i] = std::complex(value.real().derivative, value.imag().derivative); - } - return result; -} - std::vector > DescriptorEvaluator::accumulate_u(const std::vector& neighbors) const { return accumulate_u(neighbors, 0); diff --git a/source/source_md/module_snap/snap_descriptor_derivative.cpp b/source/source_md/module_snap/snap_descriptor_derivative.cpp new file mode 100644 index 00000000000..3fd906a055b --- /dev/null +++ b/source/source_md/module_snap/snap_descriptor_derivative.cpp @@ -0,0 +1,199 @@ +#include "snap_descriptor.h" + +#include "source_base/constants.h" + +#include +#include + +namespace ModuleMD +{ +namespace SNAP +{ + +namespace +{ +struct Dual +{ + double value; + double derivative; + + Dual(const double value_in = 0.0, const double derivative_in = 0.0) + : value(value_in), derivative(derivative_in) + { + } +}; + +Dual operator+(const Dual& left, const Dual& right) +{ + return Dual(left.value + right.value, left.derivative + right.derivative); +} + +Dual operator-(const Dual& left, const Dual& right) +{ + return Dual(left.value - right.value, left.derivative - right.derivative); +} + +Dual operator-(const Dual& value) +{ + return Dual(-value.value, -value.derivative); +} + +Dual operator*(const Dual& left, const Dual& right) +{ + return Dual(left.value * right.value, + left.derivative * right.value + left.value * right.derivative); +} + +Dual operator/(const Dual& left, const Dual& right) +{ + const double inverse = 1.0 / right.value; + return Dual(left.value * inverse, + (left.derivative * right.value - left.value * right.derivative) * inverse * inverse); +} + +Dual operator+(const Dual& left, const double right) +{ + return left + Dual(right); +} + +Dual operator-(const Dual& left, const double right) +{ + return left - Dual(right); +} + +Dual operator*(const Dual& left, const double right) +{ + return left * Dual(right); +} + +Dual operator*(const double left, const Dual& right) +{ + return Dual(left) * right; +} + +Dual operator/(const Dual& left, const double right) +{ + return left / Dual(right); +} + +Dual operator/(const double left, const Dual& right) +{ + return Dual(left) / right; +} + +Dual& operator*=(Dual& left, const Dual& right) +{ + left = left * right; + return left; +} + +Dual& operator+=(Dual& left, const Dual& right) +{ + left = left + right; + return left; +} + +Dual dual_sqrt(const Dual& value) +{ + const double root = std::sqrt(value.value); + return Dual(root, value.derivative / (2.0 * root)); +} + +Dual dual_cos(const Dual& value) +{ + return Dual(std::cos(value.value), -std::sin(value.value) * value.derivative); +} + +Dual dual_tan(const Dual& value) +{ + const double cosine = std::cos(value.value); + return Dual(std::tan(value.value), value.derivative / (cosine * cosine)); +} +} + +UWithDerivative DescriptorEvaluator::compute_u_with_derivative(const Neighbor& neighbor, const int direction) const +{ + if (direction < 0 || direction > 2) + { + throw std::invalid_argument("SNAP derivative direction must be 0, 1, or 2."); + } + const Dual x(neighbor.x, direction == 0 ? 1.0 : 0.0); + const Dual y(neighbor.y, direction == 1 ? 1.0 : 0.0); + const Dual z(neighbor.z, direction == 2 ? 1.0 : 0.0); + const Dual rsq = x * x + y * y + z * z; + const Dual distance = dual_sqrt(rsq); + const double cutoff_radius = neighbor.cutoff_radius > 0.0 ? neighbor.cutoff_radius : parameters_.rcut; + + UWithDerivative result; + result.values.assign(u_size_, std::complex(0.0, 0.0)); + result.derivatives.assign(u_size_, std::complex(0.0, 0.0)); + if (distance.value <= 1.0e-14 || distance.value >= cutoff_radius) + { + return result; + } + + Dual scale; + if (!parameters_.switch_flag) + { + scale = Dual(1.0); + } + else if (distance.value <= parameters_.rmin) + { + scale = Dual(1.0); + } + else + { + const Dual angle = (distance - parameters_.rmin) * ModuleBase::PI + / (cutoff_radius - parameters_.rmin); + scale = 0.5 * (dual_cos(angle) + 1.0); + } + scale = scale * neighbor.weight; + + const Dual theta0 = (distance - parameters_.rmin) * parameters_.rfac0 * ModuleBase::PI + / (cutoff_radius - parameters_.rmin); + const Dual z0 = distance / dual_tan(theta0); + const Dual r0inv = 1.0 / dual_sqrt(rsq + z0 * z0); + const Dual ar = r0inv * z0; + const Dual ai = -r0inv * z; + const Dual br = r0inv * y; + const Dual bi = -r0inv * x; + std::vector > raw(u_size_, std::complex(Dual(0.0), Dual(0.0))); + raw[0] = std::complex(Dual(1.0), Dual(0.0)); + const int dimension = parameters_.twojmax + 1; + for (int j = 1; j <= parameters_.twojmax; ++j) + { + for (int mb = 0; 2 * mb <= j; ++mb) + { + raw[u_index(j, 0, mb)] = std::complex(Dual(0.0), Dual(0.0)); + for (int ma = 0; ma < j; ++ma) + { + const std::size_t current = u_index(j, ma, mb); + const std::size_t previous = u_index(j - 1, ma, mb); + const double first_root = rootpq_[static_cast((j - ma) * dimension + (j - mb))]; + const double second_root = rootpq_[static_cast((ma + 1) * dimension + (j - mb))]; + raw[current] += Dual(first_root) * std::complex(ar, -ai) * raw[previous]; + raw[current + 1] = Dual(-second_root) * std::complex(br, -bi) * raw[previous]; + } + } + for (int mb = 0; 2 * mb <= j; ++mb) + { + for (int ma = 0; ma <= j; ++ma) + { + const std::size_t left = u_index(j, ma, mb); + const std::size_t right = u_index(j, j - ma, j - mb); + const double sign = ((ma - mb) % 2 == 0) ? 1.0 : -1.0; + raw[right] = Dual(sign) * std::conj(raw[left]); + } + } + } + for (std::size_t i = 0; i < raw.size(); ++i) + { + const std::complex value = scale * raw[i]; + result.values[i] = std::complex(value.real().value, value.imag().value); + result.derivatives[i] = std::complex(value.real().derivative, value.imag().derivative); + } + return result; +} + +} // namespace SNAP +} // namespace ModuleMD diff --git a/source/source_md/module_snap/unittest/CMakeLists.txt b/source/source_md/module_snap/unittest/CMakeLists.txt index 72a5fc8f6c8..b4358603474 100644 --- a/source/source_md/module_snap/unittest/CMakeLists.txt +++ b/source/source_md/module_snap/unittest/CMakeLists.txt @@ -11,11 +11,11 @@ AddTest( AddTest( TARGET MODULE_MD_SNAP_descriptor LIBS base device - SOURCES test_snap_descriptor.cpp ../snap_descriptor.cpp ../snap_model.cpp ../snap_clebsch_gordan.cpp + SOURCES test_snap_descriptor.cpp ../snap_descriptor.cpp ../snap_descriptor_derivative.cpp ../snap_model.cpp ../snap_clebsch_gordan.cpp ) AddTest( TARGET MODULE_MD_SNAP_calculator LIBS base device - SOURCES test_snap_calculator.cpp ../snap_calculator.cpp ../snap_descriptor.cpp ../snap_model.cpp ../snap_clebsch_gordan.cpp + SOURCES test_snap_calculator.cpp ../snap_calculator.cpp ../snap_descriptor.cpp ../snap_descriptor_derivative.cpp ../snap_model.cpp ../snap_clebsch_gordan.cpp ) From 47543b34cea6ba26c4428d98ab66d3816ffc6678 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Thu, 29 Oct 2026 22:11:17 +0800 Subject: [PATCH 08/33] ci: rerun PR checks From bf20cc502652eca5e3b331e9b82babebef2e29e5 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Sun, 1 Nov 2026 22:44:10 +0800 Subject: [PATCH 09/33] fix: validate and implement SNAP inner switching and boundary forces --- source/source_esolver/esolver_snap.cpp | 19 +++- .../source_md/module_snap/snap_descriptor.cpp | 50 +++++++--- .../source_md/module_snap/snap_descriptor.h | 9 +- .../snap_descriptor_derivative.cpp | 25 ++--- source/source_md/module_snap/snap_model.cpp | 94 +++++++++++++++++++ source/source_md/module_snap/snap_model.h | 3 + .../unittest/test_snap_calculator.cpp | 84 +++++++++++++++++ .../module_snap/unittest/test_snap_model.cpp | 58 ++++++++++++ tests/04_FF/102_SNAP_minimal/result.ref | 4 +- tests/04_FF/103_SNAP_periodic/INPUT | 12 +++ tests/04_FF/103_SNAP_periodic/README | 6 ++ tests/04_FF/103_SNAP_periodic/STRU | 19 ++++ tests/04_FF/103_SNAP_periodic/result.ref | 5 + tests/04_FF/103_SNAP_periodic/snap.coeff | 62 ++++++++++++ tests/04_FF/103_SNAP_periodic/snap.param | 10 ++ tests/04_FF/104_SNAP_inner/INPUT | 12 +++ tests/04_FF/104_SNAP_inner/README | 10 ++ tests/04_FF/104_SNAP_inner/STRU | 19 ++++ tests/04_FF/104_SNAP_inner/result.ref | 5 + tests/04_FF/104_SNAP_inner/snap.coeff | 62 ++++++++++++ tests/04_FF/104_SNAP_inner/snap.param | 13 +++ tests/04_FF/CASES_CPU.txt | 2 + 22 files changed, 546 insertions(+), 37 deletions(-) create mode 100644 tests/04_FF/103_SNAP_periodic/INPUT create mode 100644 tests/04_FF/103_SNAP_periodic/README create mode 100644 tests/04_FF/103_SNAP_periodic/STRU create mode 100644 tests/04_FF/103_SNAP_periodic/result.ref create mode 100644 tests/04_FF/103_SNAP_periodic/snap.coeff create mode 100644 tests/04_FF/103_SNAP_periodic/snap.param create mode 100644 tests/04_FF/104_SNAP_inner/INPUT create mode 100644 tests/04_FF/104_SNAP_inner/README create mode 100644 tests/04_FF/104_SNAP_inner/STRU create mode 100644 tests/04_FF/104_SNAP_inner/result.ref create mode 100644 tests/04_FF/104_SNAP_inner/snap.coeff create mode 100644 tests/04_FF/104_SNAP_inner/snap.param diff --git a/source/source_esolver/esolver_snap.cpp b/source/source_esolver/esolver_snap.cpp index f3f3d979054..01f5f785b01 100644 --- a/source/source_esolver/esolver_snap.cpp +++ b/source/source_esolver/esolver_snap.cpp @@ -36,6 +36,13 @@ ModuleMD::SNAP::Neighbor make_neighbor(const NeighborAtom& center, + parameters.element_radii[static_cast(neighbor.atom_type)]) * parameters.rcutfac; result.element_index = static_cast(neighbor.atom_type); + if (parameters.switchinner_flag) + { + const std::size_t center_type = static_cast(center.atom_type); + const std::size_t neighbor_type = static_cast(neighbor.atom_type); + result.sinner = 0.5 * (parameters.sinner[center_type] + parameters.sinner[neighbor_type]); + result.dinner = 0.5 * (parameters.dinner[center_type] + parameters.dinner[neighbor_type]); + } return result; } } @@ -152,18 +159,22 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) } } } + const double force_scale = 1.0 / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU); for (std::size_t i = 0; i < mdcell.ghost_atoms().size(); ++i) { - mdcell.ghost_atoms()[i].force = all_force[nowned + i]; + const ModuleBase::Vector3& value = all_force[nowned + i]; + mdcell.ghost_atoms()[i].force.set(value.x * force_scale, + value.y * force_scale, + value.z * force_scale); } Parallel_Reduce::reduce_all(snap_potential_); Parallel_Reduce::reduce_all(snap_virial_.c, 9); for (int i = 0; i < nowned; ++i) { owned_atoms[static_cast(i)].force.set( - all_force[static_cast(i)].x / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU), - all_force[static_cast(i)].y / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU), - all_force[static_cast(i)].z / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU)); + all_force[static_cast(i)].x * force_scale, + all_force[static_cast(i)].y * force_scale, + all_force[static_cast(i)].z * force_scale); } return; } diff --git a/source/source_md/module_snap/snap_descriptor.cpp b/source/source_md/module_snap/snap_descriptor.cpp index bc2642ec827..a0c33db3b64 100644 --- a/source/source_md/module_snap/snap_descriptor.cpp +++ b/source/source_md/module_snap/snap_descriptor.cpp @@ -65,23 +65,45 @@ std::size_t DescriptorEvaluator::u_index(const int j, const int ma, const int mb return u_block_[static_cast(j)] + static_cast(mb * (j + 1) + ma); } -double DescriptorEvaluator::cutoff(const double distance, const double cutoff_radius) const +DescriptorEvaluator::SwitchValue DescriptorEvaluator::switching(const double distance, + const Neighbor& neighbor, + const double cutoff_radius) const { - if (!parameters_.switch_flag) + SwitchValue result; + result.value = 1.0; + result.derivative = 0.0; + if (distance >= cutoff_radius) { - return distance < cutoff_radius ? 1.0 : 0.0; + result.value = 0.0; + return result; } - if (distance <= parameters_.rmin) + if (parameters_.switch_flag && distance > parameters_.rmin) { - return 1.0; + const double angle_scale = ModuleBase::PI / (cutoff_radius - parameters_.rmin); + const double angle = (distance - parameters_.rmin) * angle_scale; + result.value = 0.5 * (std::cos(angle) + 1.0); + result.derivative = -0.5 * std::sin(angle) * angle_scale; } - if (distance >= cutoff_radius) + if (parameters_.switchinner_flag) { - return 0.0; + const double inner_start = neighbor.sinner - neighbor.dinner; + const double inner_end = neighbor.sinner + neighbor.dinner; + if (distance <= inner_start) + { + result.value = 0.0; + result.derivative = 0.0; + } + else if (distance < inner_end) + { + const double angle_scale = 0.5 * ModuleBase::PI / neighbor.dinner; + const double angle = (distance - inner_start) * angle_scale; + const double inner_value = 0.5 * (1.0 - std::cos(angle)); + const double inner_derivative = 0.5 * std::sin(angle) * angle_scale; + result.derivative = result.derivative * inner_value + result.value * inner_derivative; + result.value *= inner_value; + } } - const double angle = ModuleBase::PI * (distance - parameters_.rmin) - / (cutoff_radius - parameters_.rmin); - return 0.5 * (std::cos(angle) + 1.0); + return result; } std::vector > DescriptorEvaluator::compute_u(const Neighbor& neighbor) const @@ -90,10 +112,14 @@ std::vector > DescriptorEvaluator::compute_u(const Neighbor const double distance = std::sqrt(rsq); const double cutoff_radius = neighbor.cutoff_radius > 0.0 ? neighbor.cutoff_radius : parameters_.rcut; std::vector > result(u_size_, std::complex(0.0, 0.0)); - if (distance <= 1.0e-14 || cutoff(distance, cutoff_radius) == 0.0) + if (distance <= 1.0e-14 || switching(distance, neighbor, cutoff_radius).value == 0.0) { return result; } + if (distance <= parameters_.rmin) + { + throw std::domain_error("SNAP neighbor distance must be greater than rmin0."); + } const double theta0 = (distance - parameters_.rmin) * parameters_.rfac0 * ModuleBase::PI / (cutoff_radius - parameters_.rmin); @@ -176,7 +202,7 @@ std::vector > DescriptorEvaluator::accumulate_u(const std:: } const double distance = std::sqrt(neighbor.x * neighbor.x + neighbor.y * neighbor.y + neighbor.z * neighbor.z); const double cutoff_radius = neighbor.cutoff_radius > 0.0 ? neighbor.cutoff_radius : parameters_.rcut; - const double scale = cutoff(distance, cutoff_radius) * neighbor.weight; + const double scale = switching(distance, neighbor, cutoff_radius).value * neighbor.weight; if (scale == 0.0) { continue; diff --git a/source/source_md/module_snap/snap_descriptor.h b/source/source_md/module_snap/snap_descriptor.h index e12acaedf42..a20f495bac4 100644 --- a/source/source_md/module_snap/snap_descriptor.h +++ b/source/source_md/module_snap/snap_descriptor.h @@ -20,6 +20,8 @@ struct Neighbor double weight = 1.0; double cutoff_radius = 0.0; std::size_t element_index = 0; + double sinner = 0.0; + double dinner = 0.0; }; struct UWithDerivative @@ -63,6 +65,11 @@ class DescriptorEvaluator } private: + struct SwitchValue + { + double value; + double derivative; + }; struct BispectrumIndex { int j1; @@ -71,7 +78,7 @@ class DescriptorEvaluator }; std::size_t u_index(int j, int ma, int mb) const; - double cutoff(double distance, double cutoff_radius) const; + SwitchValue switching(double distance, const Neighbor& neighbor, double cutoff_radius) const; void compute_rootpq(); ModelParameters parameters_; diff --git a/source/source_md/module_snap/snap_descriptor_derivative.cpp b/source/source_md/module_snap/snap_descriptor_derivative.cpp index 3fd906a055b..9351636bc3f 100644 --- a/source/source_md/module_snap/snap_descriptor_derivative.cpp +++ b/source/source_md/module_snap/snap_descriptor_derivative.cpp @@ -99,11 +99,6 @@ Dual dual_sqrt(const Dual& value) return Dual(root, value.derivative / (2.0 * root)); } -Dual dual_cos(const Dual& value) -{ - return Dual(std::cos(value.value), -std::sin(value.value) * value.derivative); -} - Dual dual_tan(const Dual& value) { const double cosine = std::cos(value.value); @@ -131,23 +126,17 @@ UWithDerivative DescriptorEvaluator::compute_u_with_derivative(const Neighbor& n { return result; } - - Dual scale; - if (!parameters_.switch_flag) + const SwitchValue switch_value = switching(distance.value, neighbor, cutoff_radius); + if (switch_value.value == 0.0) { - scale = Dual(1.0); - } - else if (distance.value <= parameters_.rmin) - { - scale = Dual(1.0); + return result; } - else + if (distance.value <= parameters_.rmin) { - const Dual angle = (distance - parameters_.rmin) * ModuleBase::PI - / (cutoff_radius - parameters_.rmin); - scale = 0.5 * (dual_cos(angle) + 1.0); + throw std::domain_error("SNAP neighbor distance must be greater than rmin0."); } - scale = scale * neighbor.weight; + const Dual scale(switch_value.value * neighbor.weight, + switch_value.derivative * distance.derivative * neighbor.weight); const Dual theta0 = (distance - parameters_.rmin) * parameters_.rfac0 * ModuleBase::PI / (cutoff_radius - parameters_.rmin); diff --git a/source/source_md/module_snap/snap_model.cpp b/source/source_md/module_snap/snap_model.cpp index 4c62c864265..3d1e56d69f5 100644 --- a/source/source_md/module_snap/snap_model.cpp +++ b/source/source_md/module_snap/snap_model.cpp @@ -84,6 +84,11 @@ bool ModelParameters::valid(std::string& error) const error = "SNAP element names and radii must have the same size."; return false; } + if (switchinner_flag && (sinner.size() != elements.size() || dinner.size() != elements.size())) + { + error = "SNAP switchinnerflag requires sinner and dinner values for every element."; + return false; + } for (std::size_t i = 0; i < element_weights.size(); ++i) { if (!std::isfinite(element_weights[i]) || !std::isfinite(element_radii[i]) || element_radii[i] <= 0.0) @@ -91,6 +96,24 @@ bool ModelParameters::valid(std::string& error) const error = "SNAP element weights must be finite."; return false; } + if (switchinner_flag && (!std::isfinite(sinner[i]) || !std::isfinite(dinner[i]) || dinner[i] <= 0.0)) + { + error = "SNAP sinner must be finite and dinner must be finite and positive."; + return false; + } + } + for (std::size_t i = 0; i < element_radii.size(); ++i) + { + for (std::size_t j = i; j < element_radii.size(); ++j) + { + const double pair_cutoff = (element_radii[i] + element_radii[j]) * rcutfac; + if (!std::isfinite(pair_cutoff) || rmin >= pair_cutoff) + { + error = "SNAP rmin0 must be smaller than the cutoff for element pair " + + elements[i] + "-" + elements[j] + "."; + return false; + } + } } return true; } @@ -100,6 +123,7 @@ bool ModelData::load(const std::string& coefficient_file, const std::vector& requested_elements, std::string& error) { + error.clear(); parameters = ModelParameters(); parameters.rfac0 = 0.99363; coefficients.clear(); @@ -206,6 +230,8 @@ bool ModelData::load(const std::string& coefficient_file, } bool has_rcutfac = false; bool has_twojmax = false; + bool has_sinner = false; + bool has_dinner = false; while (next_data_line(parameter_stream, line)) { std::istringstream words(line); @@ -295,6 +321,74 @@ bool ModelData::load(const std::string& coefficient_file, } parameters.chem_flag = value != 0; } + else if (keyword == "switchinnerflag") + { + int value = 0; + if (!read_parameter_value(words, value, keyword, error)) + { + return false; + } + if (value != 0 && value != 1) + { + error = "SNAP switchinnerflag must be 0 or 1."; + return false; + } + parameters.switchinner_flag = value == 1; + } + else if (keyword == "sinner" || keyword == "dinner") + { + std::vector& values = keyword == "sinner" ? parameters.sinner : parameters.dinner; + values.resize(parameters.elements.size()); + for (std::size_t i = 0; i < values.size(); ++i) + { + if (!read_parameter_value(words, values[i], keyword, error)) + { + return false; + } + } + if (keyword == "sinner") + { + has_sinner = true; + } + else + { + has_dinner = true; + } + } + else if (keyword == "chunksize" || keyword == "parallelthresh") + { + int value = 0; + if (!read_parameter_value(words, value, keyword, error)) + { + return false; + } + if (value <= 0) + { + error = "SNAP " + keyword + " must be positive."; + return false; + } + } + else + { + error = "Unknown SNAP parameter: " + keyword; + return false; + } + std::string extra; + if (words >> extra) + { + error = "Unexpected extra value for SNAP parameter: " + keyword; + return false; + } + } + if (parameters.switchinner_flag && (!has_sinner || !has_dinner)) + { + error = "SNAP switchinnerflag=1 requires sinner and dinner."; + return false; + } + if (!parameters.switchinner_flag && (has_sinner || has_dinner)) + { + error = "SNAP sinner and dinner require switchinnerflag=1."; + return false; } if (!has_rcutfac || !has_twojmax) { diff --git a/source/source_md/module_snap/snap_model.h b/source/source_md/module_snap/snap_model.h index 356a1e9cd4f..806018c19b3 100644 --- a/source/source_md/module_snap/snap_model.h +++ b/source/source_md/module_snap/snap_model.h @@ -22,10 +22,13 @@ struct ModelParameters bool bzero_flag = true; bool quadratic_flag = false; bool wselfall_flag = false; + bool switchinner_flag = false; double wself = 1.0; std::vector elements; std::vector element_weights; std::vector element_radii; + std::vector sinner; + std::vector dinner; bool valid(std::string& error) const; }; diff --git a/source/source_md/module_snap/unittest/test_snap_calculator.cpp b/source/source_md/module_snap/unittest/test_snap_calculator.cpp index 7ef14734e63..076486aee71 100644 --- a/source/source_md/module_snap/unittest/test_snap_calculator.cpp +++ b/source/source_md/module_snap/unittest/test_snap_calculator.cpp @@ -167,4 +167,88 @@ TEST(SnapCalculator, AnalyticForceMatchesFiniteDifference) } } +TEST(SnapCalculator, InnerSwitchMatchesFiniteDifference) +{ + ModuleMD::SNAP::ModelData model = make_model(); + model.parameters.twojmax = 2; + model.parameters.switchinner_flag = true; + model.parameters.sinner.push_back(1.5); + model.parameters.dinner.push_back(0.4); + model.coefficients[0] = {0.2, 0.3, -0.1, 0.5, 0.2, -0.4}; + const ModuleMD::SNAP::Calculator calculator(model); + ModuleMD::SNAP::Neighbor first; + first.x = 1.4; + first.y = 0.3; + first.z = 0.2; + first.sinner = 1.5; + first.dinner = 0.4; + ModuleMD::SNAP::Neighbor second = first; + second.x = -0.3; + second.y = 1.7; + second.z = -0.2; + const std::vector neighbors = {first, second}; + const ModuleMD::SNAP::ForceResult analytic = calculator.compute_with_analytic_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult finite = calculator.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); + for (std::size_t i = 0; i < neighbors.size(); ++i) + { + for (int direction = 0; direction < 3; ++direction) + { + EXPECT_NEAR(analytic.neighbor_forces[i][static_cast(direction)], + finite.neighbor_forces[i][static_cast(direction)], 1.0e-5); + } + } + + model.parameters.quadratic_flag = true; + model.coefficients[0].resize(21, 0.0); + model.coefficients[0][6] = 0.25; + model.coefficients[0][10] = -0.15; + const ModuleMD::SNAP::Calculator quadratic(model); + const ModuleMD::SNAP::ForceResult quadratic_analytic = quadratic.compute_with_analytic_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult quadratic_finite = quadratic.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); + for (std::size_t i = 0; i < neighbors.size(); ++i) + { + for (int direction = 0; direction < 3; ++direction) + { + EXPECT_NEAR(quadratic_analytic.neighbor_forces[i][static_cast(direction)], + quadratic_finite.neighbor_forces[i][static_cast(direction)], 1.0e-5); + } + } +} + +TEST(SnapCalculator, InnerSwitchSkipsSingularRadius) +{ + ModuleMD::SNAP::ModelData model = make_model(); + model.parameters.rmin = 0.5; + model.parameters.switchinner_flag = true; + model.parameters.sinner.push_back(1.5); + model.parameters.dinner.push_back(0.4); + const ModuleMD::SNAP::Calculator calculator(model); + ModuleMD::SNAP::Neighbor neighbor; + neighbor.x = 0.5; + neighbor.sinner = 1.5; + neighbor.dinner = 0.4; + const std::vector neighbors(1, neighbor); + EXPECT_NO_THROW(calculator.compute_with_analytic_force(neighbors, 0)); + model.parameters.switchinner_flag = false; + const ModuleMD::SNAP::Calculator bare(model); + EXPECT_THROW(bare.compute(neighbors, 0), std::domain_error); + EXPECT_THROW(bare.compute_with_analytic_force(neighbors, 0), std::domain_error); + + model.parameters.twojmax = 2; + model.coefficients[0] = {0.2, 0.3, -0.1, 0.5, 0.2, -0.4}; + const ModuleMD::SNAP::Calculator angular(model); + neighbor.x = 0.55; + neighbor.y = 0.12; + const std::vector near_neighbors(1, neighbor); + const ModuleMD::SNAP::ForceResult near_analytic = angular.compute_with_analytic_force(near_neighbors, 0); + const ModuleMD::SNAP::ForceResult near_finite = angular.compute_with_finite_difference_force(near_neighbors, 0, 1.0e-6); + EXPECT_TRUE(std::isfinite(near_analytic.energy.energy)); + for (int direction = 0; direction < 3; ++direction) + { + EXPECT_TRUE(std::isfinite(near_analytic.neighbor_forces[0][static_cast(direction)])); + EXPECT_NEAR(near_analytic.neighbor_forces[0][static_cast(direction)], + near_finite.neighbor_forces[0][static_cast(direction)], 1.0e-4); + } +} + } // namespace diff --git a/source/source_md/module_snap/unittest/test_snap_model.cpp b/source/source_md/module_snap/unittest/test_snap_model.cpp index 0d7a0873433..a053c4fd226 100644 --- a/source/source_md/module_snap/unittest/test_snap_model.cpp +++ b/source/source_md/module_snap/unittest/test_snap_model.cpp @@ -56,6 +56,21 @@ TEST(SnapModel, RejectsInvalidRadialRange) EXPECT_FALSE(error.empty()); } +TEST(SnapModel, RejectsRminOutsideSmallPairCutoff) +{ + ModuleMD::SNAP::ModelParameters parameters; + parameters.rcut = 4.0; + parameters.rcutfac = 1.0; + parameters.rmin = 1.5; + parameters.rfac0 = 0.99363; + parameters.elements = {"Small", "Large"}; + parameters.element_weights = {1.0, 1.0}; + parameters.element_radii = {0.5, 2.0}; + std::string error; + EXPECT_FALSE(parameters.valid(error)); + EXPECT_NE(error.find("Small-Small"), std::string::npos); +} + TEST(SnapModel, LoadsLammpsStyleCoefficientAndParameterFiles) { const std::string coefficient_file = testing::TempDir() + "snap_coeff_test.txt"; @@ -168,4 +183,47 @@ TEST(SnapModel, LoadsChemicalCoefficientBlocks) std::remove(parameter_file.c_str()); } +TEST(SnapModel, ReadsInnerSwitchAndRejectsUnknownParameter) +{ + const std::string coefficient_file = testing::TempDir() + "snap_inner_coeff.txt"; + const std::string parameter_file = testing::TempDir() + "snap_inner_param.txt"; + { + std::ofstream output(coefficient_file.c_str()); + output << "1 2\nSi 2.0 1.0\n0.0\n1.0\n"; + } + { + std::ofstream output(parameter_file.c_str()); + output << "rcutfac 1.0\ntwojmax 0\nswitchinnerflag 1\n"; + output << "sinner 1.5\ndinner 0.4\nchunksize 1024\n"; + } + ModuleMD::SNAP::ModelData model; + std::string error; + const std::vector elements(1, "Si"); + ASSERT_TRUE(model.load(coefficient_file, parameter_file, elements, error)) << error; + EXPECT_TRUE(model.parameters.switchinner_flag); + ASSERT_EQ(model.parameters.sinner.size(), static_cast(1)); + EXPECT_DOUBLE_EQ(model.parameters.sinner[0], 1.5); + { + std::ofstream output(parameter_file.c_str(), std::ios::app); + output << "unsupported_option 1\n"; + } + EXPECT_FALSE(model.load(coefficient_file, parameter_file, elements, error)); + EXPECT_NE(error.find("unsupported_option"), std::string::npos); + { + std::ofstream output(parameter_file.c_str()); + output << "rcutfac 1.0\ntwojmax 0\nswitchinnerflag 1\nsinner 1.5\n"; + } + error.clear(); + EXPECT_FALSE(model.load(coefficient_file, parameter_file, elements, error)); + EXPECT_NE(error.find("requires sinner and dinner"), std::string::npos); + { + std::ofstream output(parameter_file.c_str()); + output << "rcutfac 1.0\ntwojmax 0\nswitchinnerflag 0\n"; + } + error.clear(); + EXPECT_TRUE(model.load(coefficient_file, parameter_file, elements, error)) << error; + std::remove(coefficient_file.c_str()); + std::remove(parameter_file.c_str()); +} + } // namespace diff --git a/tests/04_FF/102_SNAP_minimal/result.ref b/tests/04_FF/102_SNAP_minimal/result.ref index 3a0762311ec..9a188a922ac 100644 --- a/tests/04_FF/102_SNAP_minimal/result.ref +++ b/tests/04_FF/102_SNAP_minimal/result.ref @@ -1,5 +1,5 @@ -etotref -0.621502 +etotref -0.62150213 etotperatomref -0.3107510650 totalforceref 5.604078 -totalstressref -4.007952 +totalstressref 4.007952 totaltimeref 35.66 diff --git a/tests/04_FF/103_SNAP_periodic/INPUT b/tests/04_FF/103_SNAP_periodic/INPUT new file mode 100644 index 00000000000..0ed0eb5b3ab --- /dev/null +++ b/tests/04_FF/103_SNAP_periodic/INPUT @@ -0,0 +1,12 @@ +INPUT_PARAMETERS +calculation md +suffix autotest +esolver_type snap +pot_file snap.coeff +snap_param_file snap.param +cal_force 1 +cal_stress 1 +md_nstep 1 +md_type nve +md_dt 1 +init_vel 0 diff --git a/tests/04_FF/103_SNAP_periodic/README b/tests/04_FF/103_SNAP_periodic/README new file mode 100644 index 00000000000..0f19eccb7bf --- /dev/null +++ b/tests/04_FF/103_SNAP_periodic/README @@ -0,0 +1,6 @@ +CPU SNAP periodic-image regression case. + +This uses the same potential and two-atom separation as 102_SNAP_minimal, +but places the atoms on opposite sides of the periodic boundary. Their +energy, force magnitude, and stress must match the unwrapped case. The +periodic neighbor contributes through the MDCell ghost-force return path. diff --git a/tests/04_FF/103_SNAP_periodic/STRU b/tests/04_FF/103_SNAP_periodic/STRU new file mode 100644 index 00000000000..2938b4c6e2b --- /dev/null +++ b/tests/04_FF/103_SNAP_periodic/STRU @@ -0,0 +1,19 @@ +ATOMIC_SPECIES +Si 28.0855 auto auto + +LATTICE_CONSTANT +1.0 + +LATTICE_VECTORS +20.0 0.0 0.0 +0.0 20.0 0.0 +0.0 0.0 20.0 + +ATOMIC_POSITIONS +Cartesian + +Si +0 +2 +1.0 0.0 0.0 m 1 1 1 +19.0 0.0 0.0 m 1 1 1 diff --git a/tests/04_FF/103_SNAP_periodic/result.ref b/tests/04_FF/103_SNAP_periodic/result.ref new file mode 100644 index 00000000000..9a188a922ac --- /dev/null +++ b/tests/04_FF/103_SNAP_periodic/result.ref @@ -0,0 +1,5 @@ +etotref -0.62150213 +etotperatomref -0.3107510650 +totalforceref 5.604078 +totalstressref 4.007952 +totaltimeref 35.66 diff --git a/tests/04_FF/103_SNAP_periodic/snap.coeff b/tests/04_FF/103_SNAP_periodic/snap.coeff new file mode 100644 index 00000000000..fc13f2f7b43 --- /dev/null +++ b/tests/04_FF/103_SNAP_periodic/snap.coeff @@ -0,0 +1,62 @@ +# ABACUS-generated SNAP regression fixture +# This deterministic coefficient set is created for software testing only. +# It is not a transferable or physically validated material potential. + +1 56 +Si 0.5 1 +0.125000000000 +-0.002000000000 +0.003000000000 +-0.004000000000 +0.005000000000 +-0.006000000000 +0.007000000000 +-0.008000000000 +0.009000000000 +-0.010000000000 +0.011000000000 +-0.012000000000 +0.013000000000 +-0.014000000000 +0.015000000000 +-0.016000000000 +0.017000000000 +-0.018000000000 +0.019000000000 +-0.020000000000 +0.021000000000 +-0.022000000000 +0.023000000000 +-0.024000000000 +0.025000000000 +-0.026000000000 +0.027000000000 +-0.028000000000 +0.029000000000 +-0.030000000000 +0.031000000000 +-0.032000000000 +0.033000000000 +-0.034000000000 +0.035000000000 +-0.036000000000 +0.037000000000 +-0.038000000000 +0.039000000000 +-0.040000000000 +0.041000000000 +-0.042000000000 +0.043000000000 +-0.044000000000 +0.045000000000 +-0.046000000000 +0.047000000000 +-0.048000000000 +0.049000000000 +-0.050000000000 +0.051000000000 +-0.052000000000 +0.053000000000 +-0.054000000000 +0.055000000000 +-0.056000000000 diff --git a/tests/04_FF/103_SNAP_periodic/snap.param b/tests/04_FF/103_SNAP_periodic/snap.param new file mode 100644 index 00000000000..23e0d83d38b --- /dev/null +++ b/tests/04_FF/103_SNAP_periodic/snap.param @@ -0,0 +1,10 @@ +# ABACUS-generated SNAP regression fixture +# This deterministic parameter set is created for software testing only. +# It is not a transferable or physically validated material potential. + +rcutfac 4.9 +twojmax 8 +rfac0 0.99363 +rmin0 0 +quadraticflag 0 +bzeroflag 0 diff --git a/tests/04_FF/104_SNAP_inner/INPUT b/tests/04_FF/104_SNAP_inner/INPUT new file mode 100644 index 00000000000..0ed0eb5b3ab --- /dev/null +++ b/tests/04_FF/104_SNAP_inner/INPUT @@ -0,0 +1,12 @@ +INPUT_PARAMETERS +calculation md +suffix autotest +esolver_type snap +pot_file snap.coeff +snap_param_file snap.param +cal_force 1 +cal_stress 1 +md_nstep 1 +md_type nve +md_dt 1 +init_vel 0 diff --git a/tests/04_FF/104_SNAP_inner/README b/tests/04_FF/104_SNAP_inner/README new file mode 100644 index 00000000000..8c436ba5c3c --- /dev/null +++ b/tests/04_FF/104_SNAP_inner/README @@ -0,0 +1,10 @@ +CPU SNAP inner-switch regression case. + +The atoms are inside the smooth inner-switch interval (0.8 to 1.2 Angstrom). +This case verifies model-file parsing and the complete MD energy, force, and +stress path with switchinnerflag enabled. The coefficients are a deterministic +software-test fixture, not a validated physical potential. + +The reference was cross-checked with LAMMPS SNAP (30 Mar 2026 development +build, c46bbef): potential energy -0.24612388 eV, x forces -2.7962 and ++2.7962 eV/Angstrom, and Pxx 3999.6081 bar. ABACUS reports Pxx in kbar. diff --git a/tests/04_FF/104_SNAP_inner/STRU b/tests/04_FF/104_SNAP_inner/STRU new file mode 100644 index 00000000000..8e59e8a0b97 --- /dev/null +++ b/tests/04_FF/104_SNAP_inner/STRU @@ -0,0 +1,19 @@ +ATOMIC_SPECIES +Si 28.0855 auto auto + +LATTICE_CONSTANT +1.0 + +LATTICE_VECTORS +20.0 0.0 0.0 +0.0 20.0 0.0 +0.0 0.0 20.0 + +ATOMIC_POSITIONS +Cartesian + +Si +0 +2 +0.0 0.0 0.0 m 1 1 1 +2.0 0.0 0.0 m 1 1 1 diff --git a/tests/04_FF/104_SNAP_inner/result.ref b/tests/04_FF/104_SNAP_inner/result.ref new file mode 100644 index 00000000000..c5b2fa6a682 --- /dev/null +++ b/tests/04_FF/104_SNAP_inner/result.ref @@ -0,0 +1,5 @@ +etotref -0.24612388 +etotperatomref -0.1230619400 +totalforceref 5.592410 +totalstressref 3.999606 +totaltimeref 3.91 diff --git a/tests/04_FF/104_SNAP_inner/snap.coeff b/tests/04_FF/104_SNAP_inner/snap.coeff new file mode 100644 index 00000000000..fc13f2f7b43 --- /dev/null +++ b/tests/04_FF/104_SNAP_inner/snap.coeff @@ -0,0 +1,62 @@ +# ABACUS-generated SNAP regression fixture +# This deterministic coefficient set is created for software testing only. +# It is not a transferable or physically validated material potential. + +1 56 +Si 0.5 1 +0.125000000000 +-0.002000000000 +0.003000000000 +-0.004000000000 +0.005000000000 +-0.006000000000 +0.007000000000 +-0.008000000000 +0.009000000000 +-0.010000000000 +0.011000000000 +-0.012000000000 +0.013000000000 +-0.014000000000 +0.015000000000 +-0.016000000000 +0.017000000000 +-0.018000000000 +0.019000000000 +-0.020000000000 +0.021000000000 +-0.022000000000 +0.023000000000 +-0.024000000000 +0.025000000000 +-0.026000000000 +0.027000000000 +-0.028000000000 +0.029000000000 +-0.030000000000 +0.031000000000 +-0.032000000000 +0.033000000000 +-0.034000000000 +0.035000000000 +-0.036000000000 +0.037000000000 +-0.038000000000 +0.039000000000 +-0.040000000000 +0.041000000000 +-0.042000000000 +0.043000000000 +-0.044000000000 +0.045000000000 +-0.046000000000 +0.047000000000 +-0.048000000000 +0.049000000000 +-0.050000000000 +0.051000000000 +-0.052000000000 +0.053000000000 +-0.054000000000 +0.055000000000 +-0.056000000000 diff --git a/tests/04_FF/104_SNAP_inner/snap.param b/tests/04_FF/104_SNAP_inner/snap.param new file mode 100644 index 00000000000..b73ae7c173b --- /dev/null +++ b/tests/04_FF/104_SNAP_inner/snap.param @@ -0,0 +1,13 @@ +# ABACUS-generated SNAP regression fixture +# This deterministic parameter set is created for software testing only. +# It is not a transferable or physically validated material potential. + +rcutfac 4.9 +twojmax 8 +rfac0 0.99363 +rmin0 0 +switchinnerflag 1 +sinner 1.0 +dinner 0.2 +quadraticflag 0 +bzeroflag 0 diff --git a/tests/04_FF/CASES_CPU.txt b/tests/04_FF/CASES_CPU.txt index 5beefe612c9..06b80b22255 100644 --- a/tests/04_FF/CASES_CPU.txt +++ b/tests/04_FF/CASES_CPU.txt @@ -21,3 +21,5 @@ #50_DP_Al #101_NEP_HfO2 102_SNAP_minimal +103_SNAP_periodic +104_SNAP_inner From fa972d4844b45afe680420e82d8747f8ffef2548 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Sun, 1 Nov 2026 22:46:37 +0800 Subject: [PATCH 10/33] refactor: keep SNAP model validation focused --- source/source_md/module_snap/snap_model.cpp | 87 +++++++++++++++------ 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/source/source_md/module_snap/snap_model.cpp b/source/source_md/module_snap/snap_model.cpp index 3d1e56d69f5..6df5673d859 100644 --- a/source/source_md/module_snap/snap_model.cpp +++ b/source/source_md/module_snap/snap_model.cpp @@ -35,25 +35,77 @@ bool read_parameter_value(std::istringstream& words, T& value, const std::string } return true; } -} -namespace ModuleMD -{ -namespace SNAP +bool validate_inner(const ModuleMD::SNAP::ModelParameters& parameters, std::string& error) { + if (!parameters.switchinner_flag) + { + return true; + } + const std::size_t count = parameters.elements.size(); + if (parameters.sinner.size() != count || parameters.dinner.size() != count) + { + error = "SNAP switchinnerflag requires sinner and dinner values for every element."; + return false; + } + for (std::size_t i = 0; i < count; ++i) + { + if (!std::isfinite(parameters.sinner[i]) || !std::isfinite(parameters.dinner[i]) + || parameters.dinner[i] <= 0.0) + { + error = "SNAP sinner must be finite and dinner must be finite and positive."; + return false; + } + } + return true; +} -bool ModelParameters::valid(std::string& error) const +bool validate_cutoff(const ModuleMD::SNAP::ModelParameters& parameters, std::string& error) { - if (!std::isfinite(rcut) || rcut <= 0.0) + if (!std::isfinite(parameters.rcut) || parameters.rcut <= 0.0) { error = "SNAP cutoff must be finite and positive."; return false; } - if (!std::isfinite(rcutfac) || rcutfac <= 0.0) + if (!std::isfinite(parameters.rcutfac) || parameters.rcutfac <= 0.0) { error = "SNAP rcutfac must be finite and positive."; return false; } + return true; +} + +bool validate_pair_cutoffs(const ModuleMD::SNAP::ModelParameters& parameters, std::string& error) +{ + for (std::size_t i = 0; i < parameters.element_radii.size(); ++i) + { + for (std::size_t j = i; j < parameters.element_radii.size(); ++j) + { + const double pair_cutoff = (parameters.element_radii[i] + parameters.element_radii[j]) + * parameters.rcutfac; + if (!std::isfinite(pair_cutoff) || parameters.rmin >= pair_cutoff) + { + error = "SNAP rmin0 must be smaller than the cutoff for element pair " + + parameters.elements[i] + "-" + parameters.elements[j] + "."; + return false; + } + } + } + return true; +} +} + +namespace ModuleMD +{ +namespace SNAP +{ + +bool ModelParameters::valid(std::string& error) const +{ + if (!validate_cutoff(*this, error)) + { + return false; + } if (!std::isfinite(rmin) || rmin < 0.0 || rmin >= rcut) { error = "SNAP rmin must satisfy 0 <= rmin < rcut."; @@ -84,9 +136,8 @@ bool ModelParameters::valid(std::string& error) const error = "SNAP element names and radii must have the same size."; return false; } - if (switchinner_flag && (sinner.size() != elements.size() || dinner.size() != elements.size())) + if (!validate_inner(*this, error)) { - error = "SNAP switchinnerflag requires sinner and dinner values for every element."; return false; } for (std::size_t i = 0; i < element_weights.size(); ++i) @@ -96,24 +147,10 @@ bool ModelParameters::valid(std::string& error) const error = "SNAP element weights must be finite."; return false; } - if (switchinner_flag && (!std::isfinite(sinner[i]) || !std::isfinite(dinner[i]) || dinner[i] <= 0.0)) - { - error = "SNAP sinner must be finite and dinner must be finite and positive."; - return false; - } } - for (std::size_t i = 0; i < element_radii.size(); ++i) + if (!validate_pair_cutoffs(*this, error)) { - for (std::size_t j = i; j < element_radii.size(); ++j) - { - const double pair_cutoff = (element_radii[i] + element_radii[j]) * rcutfac; - if (!std::isfinite(pair_cutoff) || rmin >= pair_cutoff) - { - error = "SNAP rmin0 must be smaller than the cutoff for element pair " - + elements[i] + "-" + elements[j] + "."; - return false; - } - } + return false; } return true; } From 5de89a481d55e4c30cf515676d66d1eb4c0c5070 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Sun, 1 Nov 2026 23:05:33 +0800 Subject: [PATCH 11/33] refactor: reuse SNAP environment during force derivatives --- source/source_md/module_snap/snap_calculator.cpp | 2 +- source/source_md/module_snap/snap_clebsch_gordan.cpp | 3 ++- .../source_md/module_snap/snap_descriptor_derivative.cpp | 9 ++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/source/source_md/module_snap/snap_calculator.cpp b/source/source_md/module_snap/snap_calculator.cpp index c8b5dac9745..6c8b8bec22b 100644 --- a/source/source_md/module_snap/snap_calculator.cpp +++ b/source/source_md/module_snap/snap_calculator.cpp @@ -84,13 +84,13 @@ ForceResult Calculator::compute_with_analytic_force(const std::vector& result.center_force.assign(3, 0.0); result.neighbor_forces.assign(neighbors.size(), std::vector(3, 0.0)); const std::vector& coefficients = model_.coefficients[central_element]; + const std::vector > u = descriptor_evaluator_.accumulate_u(neighbors, central_element); for (std::size_t neighbor_index = 0; neighbor_index < neighbors.size(); ++neighbor_index) { for (int direction = 0; direction < 3; ++direction) { const UWithDerivative u_derivative = descriptor_evaluator_.compute_u_with_derivative(neighbors[neighbor_index], direction); - std::vector > u = descriptor_evaluator_.accumulate_u(neighbors, central_element); std::vector > du(u.size(), std::complex(0.0, 0.0)); const std::size_t derivative_offset = model_.parameters.chem_flag ? neighbors[neighbor_index].element_index diff --git a/source/source_md/module_snap/snap_clebsch_gordan.cpp b/source/source_md/module_snap/snap_clebsch_gordan.cpp index 35670761ada..f2d65865662 100644 --- a/source/source_md/module_snap/snap_clebsch_gordan.cpp +++ b/source/source_md/module_snap/snap_clebsch_gordan.cpp @@ -15,8 +15,9 @@ int half_sum(const int left, const int right) } } -ClebschGordanTable::ClebschGordanTable(const int twojmax) : twojmax_(twojmax < 0 ? 0 : twojmax) +ClebschGordanTable::ClebschGordanTable(const int twojmax) { + twojmax_ = twojmax < 0 ? 0 : twojmax; for (int j1 = 0; j1 <= twojmax_; ++j1) { for (int j2 = 0; j2 <= twojmax_; ++j2) diff --git a/source/source_md/module_snap/snap_descriptor_derivative.cpp b/source/source_md/module_snap/snap_descriptor_derivative.cpp index 9351636bc3f..cea61b8a31b 100644 --- a/source/source_md/module_snap/snap_descriptor_derivative.cpp +++ b/source/source_md/module_snap/snap_descriptor_derivative.cpp @@ -112,9 +112,12 @@ UWithDerivative DescriptorEvaluator::compute_u_with_derivative(const Neighbor& n { throw std::invalid_argument("SNAP derivative direction must be 0, 1, or 2."); } - const Dual x(neighbor.x, direction == 0 ? 1.0 : 0.0); - const Dual y(neighbor.y, direction == 1 ? 1.0 : 0.0); - const Dual z(neighbor.z, direction == 2 ? 1.0 : 0.0); + const double dx = direction == 0 ? 1.0 : 0.0; + const double dy = direction == 1 ? 1.0 : 0.0; + const double dz = direction == 2 ? 1.0 : 0.0; + const Dual x(neighbor.x, dx); + const Dual y(neighbor.y, dy); + const Dual z(neighbor.z, dz); const Dual rsq = x * x + y * y + z * z; const Dual distance = dual_sqrt(rsq); const double cutoff_radius = neighbor.cutoff_radius > 0.0 ? neighbor.cutoff_radius : parameters_.rcut; From 2f0dff3d900647c23f58708cfa5f9a5a3ceef4e9 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Sun, 1 Nov 2026 23:06:36 +0800 Subject: [PATCH 12/33] fix: confirm SNAP model paths in stdout and running log --- source/source_esolver/esolver_snap.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/source/source_esolver/esolver_snap.cpp b/source/source_esolver/esolver_snap.cpp index 01f5f785b01..cf5d68c81d6 100644 --- a/source/source_esolver/esolver_snap.cpp +++ b/source/source_esolver/esolver_snap.cpp @@ -10,6 +10,8 @@ #include #include +#include +#include #include namespace ModuleESolver @@ -22,6 +24,18 @@ void fail(const std::string& message) ModuleBase::WARNING_QUIT("ESolver_SNAP", message); } +std::string full_path(const std::string& path) +{ + char* resolved = ::realpath(path.c_str(), nullptr); + if (resolved == nullptr) + { + fail("Cannot resolve SNAP file path: " + path); + } + const std::string result(resolved); + std::free(resolved); + return result; +} + ModuleMD::SNAP::Neighbor make_neighbor(const NeighborAtom& center, const NeighborAtom& neighbor, const double lat0, @@ -62,6 +76,15 @@ void ESolver_SNAP::initialize(const std::vector& labels) { fail(error); } + const std::string coefficient_path = full_path(coefficient_file_); + const std::string parameter_path = full_path(parameter_file_); + running_log_ << " Read SNAP coefficient file: " << coefficient_path << std::endl; + running_log_ << " Read SNAP parameter file: " << parameter_path << std::endl; + if (GlobalV::MY_RANK == 0) + { + std::cout << " Read SNAP coefficient file: " << coefficient_path << std::endl; + std::cout << " Read SNAP parameter file: " << parameter_path << std::endl; + } calculator_.reset(new ModuleMD::SNAP::Calculator(model_)); snap_virial_.create(3, 3); } From 7e4bc509b0d6738ad5952efda4bfc8894cd58003 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Sun, 1 Nov 2026 23:07:25 +0800 Subject: [PATCH 13/33] docs: define SNAP chemical channel order and test mapping --- docs/advanced/md.md | 22 ++++++++++++++++++- .../module_snap/unittest/test_snap_model.cpp | 8 +++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/advanced/md.md b/docs/advanced/md.md index 25c01b1c8a4..b7d7803ea9f 100644 --- a/docs/advanced/md.md +++ b/docs/advanced/md.md @@ -96,4 +96,24 @@ And the filename of DP model is specified by keyword [pot_file](./input_files/in ## NEP -If ABACUS is compiled with the Neuroevolution Potential ([NEP](https://gpumd.org/potentials/nep.html)), MD simulations using NEP models are enabled. To use this feature, set [esolver_type](./input_files/input-main.md#esolver_type) to `nep` and specify the potential file path with the [pot_file](./input_files/input-main.md#pot_file) keyword in your INPUT file. \ No newline at end of file +If ABACUS is compiled with the Neuroevolution Potential ([NEP](https://gpumd.org/potentials/nep.html)), MD simulations using NEP models are enabled. To use this feature, set [esolver_type](./input_files/input-main.md#esolver_type) to `nep` and specify the potential file path with the [pot_file](./input_files/input-main.md#pot_file) keyword in your INPUT file. + +## SNAP + +CPU SNAP calculations use `esolver_type snap`, with the coefficient file in +`pot_file` and the LAMMPS-style parameter file in `snap_param_file`. The +implementation supports linear and quadratic coefficients, chemical channels, +outer cutoff switching, and `switchinnerflag` with `sinner` and `dinner`. + +For `chemflag 1`, the chemical-channel axes of each flattened coefficient vector +follow the element order in the STRU file. Coefficient blocks are matched by +element name, so their order within `pot_file` is not significant. Reordering +the elements in STRU without reordering the chemical-channel coefficients can +change the potential. The values in `sinner` and `dinner` also follow STRU +element order. This corresponds to the first-appearance order of elements in +LAMMPS `pair_coeff` mappings. + +The CPU implementation accepts but does not use the LAMMPS GPU execution +options `chunksize` and `parallelthresh`. Unknown SNAP parameter keywords are +rejected. Each element-pair cutoff must exceed `rmin0`; a contributing neighbor +at or below `rmin0` causes an error. diff --git a/source/source_md/module_snap/unittest/test_snap_model.cpp b/source/source_md/module_snap/unittest/test_snap_model.cpp index a053c4fd226..691c56b550e 100644 --- a/source/source_md/module_snap/unittest/test_snap_model.cpp +++ b/source/source_md/module_snap/unittest/test_snap_model.cpp @@ -179,6 +179,14 @@ TEST(SnapModel, LoadsChemicalCoefficientBlocks) EXPECT_EQ(model.coefficients[0].size(), static_cast(9)); EXPECT_DOUBLE_EQ(model.coefficients[1][1], 2.0); + const std::vector reversed_elements = {"C", "Si"}; + ModuleMD::SNAP::ModelData reversed; + ASSERT_TRUE(reversed.load(coefficient_file, parameter_file, reversed_elements, error)) << error; + EXPECT_EQ(reversed.parameters.elements[0], "C"); + EXPECT_EQ(reversed.parameters.elements[1], "Si"); + EXPECT_DOUBLE_EQ(reversed.coefficients[0][1], 2.0); + EXPECT_DOUBLE_EQ(reversed.coefficients[1][1], 1.0); + std::remove(coefficient_file.c_str()); std::remove(parameter_file.c_str()); } From 0b6f11134c02201c015574962013a5f14614abba Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Sun, 1 Nov 2026 23:10:37 +0800 Subject: [PATCH 14/33] test: cross-check angular quadratic SNAP forces and virial --- .../unittest/test_snap_calculator.cpp | 97 +++++++++++++++++++ tests/04_FF/105_SNAP_angular_quadratic/INPUT | 12 +++ tests/04_FF/105_SNAP_angular_quadratic/README | 10 ++ tests/04_FF/105_SNAP_angular_quadratic/STRU | 20 ++++ .../105_SNAP_angular_quadratic/result.ref | 5 + .../105_SNAP_angular_quadratic/snap.coeff | 24 +++++ .../105_SNAP_angular_quadratic/snap.param | 6 ++ tests/04_FF/CASES_CPU.txt | 1 + 8 files changed, 175 insertions(+) create mode 100644 tests/04_FF/105_SNAP_angular_quadratic/INPUT create mode 100644 tests/04_FF/105_SNAP_angular_quadratic/README create mode 100644 tests/04_FF/105_SNAP_angular_quadratic/STRU create mode 100644 tests/04_FF/105_SNAP_angular_quadratic/result.ref create mode 100644 tests/04_FF/105_SNAP_angular_quadratic/snap.coeff create mode 100644 tests/04_FF/105_SNAP_angular_quadratic/snap.param diff --git a/source/source_md/module_snap/unittest/test_snap_calculator.cpp b/source/source_md/module_snap/unittest/test_snap_calculator.cpp index 076486aee71..2cbe6c75316 100644 --- a/source/source_md/module_snap/unittest/test_snap_calculator.cpp +++ b/source/source_md/module_snap/unittest/test_snap_calculator.cpp @@ -2,6 +2,7 @@ #include +#include #include namespace @@ -66,6 +67,68 @@ ModuleMD::SNAP::ModelData make_chemical_model() return model; } +ModuleMD::SNAP::ModelData make_angular_quadratic_model() +{ + ModuleMD::SNAP::ModelData model = make_model(); + model.parameters.twojmax = 2; + model.parameters.quadratic_flag = true; + model.coefficients[0] = {0.2, 0.3, -0.1, 0.5, 0.2, -0.4, + 0.25, 0.0, 0.0, 0.0, -0.15, + 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0}; + return model; +} + +struct SmallCellResult +{ + double energy = 0.0; + double virial_xx = 0.0; + std::array, 3> forces = {}; +}; + +SmallCellResult evaluate_small_cell(const ModuleMD::SNAP::Calculator& calculator, + const std::array, 3>& positions) +{ + SmallCellResult total; + for (std::size_t center = 0; center < positions.size(); ++center) + { + std::vector neighbors; + std::vector neighbor_indices; + for (std::size_t atom = 0; atom < positions.size(); ++atom) + { + if (atom == center) + { + continue; + } + ModuleMD::SNAP::Neighbor neighbor; + neighbor.x = positions[atom][0] - positions[center][0]; + neighbor.y = positions[atom][1] - positions[center][1]; + neighbor.z = positions[atom][2] - positions[center][2]; + neighbor.cutoff_radius = 4.5; + neighbors.push_back(neighbor); + neighbor_indices.push_back(atom); + } + const ModuleMD::SNAP::ForceResult result = calculator.compute_with_analytic_force(neighbors, 0); + total.energy += result.energy.energy; + for (int direction = 0; direction < 3; ++direction) + { + total.forces[center][static_cast(direction)] += + result.center_force[static_cast(direction)]; + } + for (std::size_t index = 0; index < neighbors.size(); ++index) + { + const std::size_t atom = neighbor_indices[index]; + for (int direction = 0; direction < 3; ++direction) + { + total.forces[atom][static_cast(direction)] += + result.neighbor_forces[index][static_cast(direction)]; + } + total.virial_xx += neighbors[index].x * result.neighbor_forces[index][0]; + } + } + return total; +} + TEST(SnapCalculator, ComputesLinearAtomicEnergy) { const ModuleMD::SNAP::Calculator calculator(make_model()); @@ -251,4 +314,38 @@ TEST(SnapCalculator, InnerSwitchSkipsSingularRadius) } } +TEST(SnapCalculator, AngularQuadraticForcesMatchLammpsAndStrain) +{ + const ModuleMD::SNAP::Calculator calculator(make_angular_quadratic_model()); + const std::array, 3> positions = {{{0.0, 0.0, 0.0}, + {1.058354, 0.0, 0.0}, + {0.2645885, 1.3229425, 0.0}}}; + const SmallCellResult result = evaluate_small_cell(calculator, positions); + const double lammps_forces[3][2] = {{67.2928038408958, 57.5476436778783}, + {-92.1399449575303, 60.5944497536836}, + {24.8471411166345, -118.142093431562}}; + EXPECT_NEAR(result.energy, 54.909561, 1.0e-5); + for (std::size_t atom = 0; atom < positions.size(); ++atom) + { + for (int direction = 0; direction < 2; ++direction) + { + EXPECT_NEAR(result.forces[atom][static_cast(direction)], + lammps_forces[atom][direction], 2.0e-4); + } + } + + const double strain = 1.0e-6; + std::array, 3> expanded = positions; + std::array, 3> contracted = positions; + for (std::size_t atom = 0; atom < positions.size(); ++atom) + { + expanded[atom][0] *= 1.0 + strain; + contracted[atom][0] *= 1.0 - strain; + } + const double expanded_energy = evaluate_small_cell(calculator, expanded).energy; + const double contracted_energy = evaluate_small_cell(calculator, contracted).energy; + const double strain_derivative = (expanded_energy - contracted_energy) / (2.0 * strain); + EXPECT_NEAR(result.virial_xx, -strain_derivative, 1.0e-3); +} + } // namespace diff --git a/tests/04_FF/105_SNAP_angular_quadratic/INPUT b/tests/04_FF/105_SNAP_angular_quadratic/INPUT new file mode 100644 index 00000000000..0ed0eb5b3ab --- /dev/null +++ b/tests/04_FF/105_SNAP_angular_quadratic/INPUT @@ -0,0 +1,12 @@ +INPUT_PARAMETERS +calculation md +suffix autotest +esolver_type snap +pot_file snap.coeff +snap_param_file snap.param +cal_force 1 +cal_stress 1 +md_nstep 1 +md_type nve +md_dt 1 +init_vel 0 diff --git a/tests/04_FF/105_SNAP_angular_quadratic/README b/tests/04_FF/105_SNAP_angular_quadratic/README new file mode 100644 index 00000000000..81aa415ee92 --- /dev/null +++ b/tests/04_FF/105_SNAP_angular_quadratic/README @@ -0,0 +1,10 @@ +CPU SNAP regression with three non-collinear atoms, twojmax=2, nonzero +angular coefficients, and nonzero quadratic coefficients. The synthetic +potential is for software testing only. Energy, force, and stress are +cross-checked against LAMMPS SNAP using the same cell and coordinates. + +LAMMPS (30 Mar 2026 development build, c46bbef) gives total potential energy +54.909561 eV, forces (eV/Angstrom) of (67.292804, 57.547644, 0), +(-92.139945, 60.594450, 0), and (24.847141, -118.142093, 0), and Pxx +-122909.08 bar. ABACUS reports stress in kbar. The calculator unit test +checks each force component and compares virial with an energy strain derivative. diff --git a/tests/04_FF/105_SNAP_angular_quadratic/STRU b/tests/04_FF/105_SNAP_angular_quadratic/STRU new file mode 100644 index 00000000000..8a6eaca3fb4 --- /dev/null +++ b/tests/04_FF/105_SNAP_angular_quadratic/STRU @@ -0,0 +1,20 @@ +ATOMIC_SPECIES +Si 28.0855 auto auto + +LATTICE_CONSTANT +1.0 + +LATTICE_VECTORS +20.0 0.0 0.0 +0.0 20.0 0.0 +0.0 0.0 20.0 + +ATOMIC_POSITIONS +Cartesian + +Si +0 +3 +0.0 0.0 0.0 m 1 1 1 +2.0 0.0 0.0 m 1 1 1 +0.5 2.5 0.0 m 1 1 1 diff --git a/tests/04_FF/105_SNAP_angular_quadratic/result.ref b/tests/04_FF/105_SNAP_angular_quadratic/result.ref new file mode 100644 index 00000000000..c7bd38b168d --- /dev/null +++ b/tests/04_FF/105_SNAP_angular_quadratic/result.ref @@ -0,0 +1,5 @@ +etotref 54.909561 +etotperatomref 18.3031870000 +totalforceref 420.564050 +totalstressref 422.994068 +totaltimeref 0.02 diff --git a/tests/04_FF/105_SNAP_angular_quadratic/snap.coeff b/tests/04_FF/105_SNAP_angular_quadratic/snap.coeff new file mode 100644 index 00000000000..aa7b790cd3f --- /dev/null +++ b/tests/04_FF/105_SNAP_angular_quadratic/snap.coeff @@ -0,0 +1,24 @@ +# Deterministic software-test coefficients for angular and quadratic SNAP. +1 21 +Si 2.25 1.0 +0.2 +0.3 +-0.1 +0.5 +0.2 +-0.4 +0.25 +0.0 +0.0 +0.0 +-0.15 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 diff --git a/tests/04_FF/105_SNAP_angular_quadratic/snap.param b/tests/04_FF/105_SNAP_angular_quadratic/snap.param new file mode 100644 index 00000000000..eebdca8cf58 --- /dev/null +++ b/tests/04_FF/105_SNAP_angular_quadratic/snap.param @@ -0,0 +1,6 @@ +rcutfac 1.0 +twojmax 2 +rfac0 0.99363 +rmin0 0.0 +quadraticflag 1 +bzeroflag 1 diff --git a/tests/04_FF/CASES_CPU.txt b/tests/04_FF/CASES_CPU.txt index 06b80b22255..f439e013927 100644 --- a/tests/04_FF/CASES_CPU.txt +++ b/tests/04_FF/CASES_CPU.txt @@ -23,3 +23,4 @@ 102_SNAP_minimal 103_SNAP_periodic 104_SNAP_inner +105_SNAP_angular_quadratic From 709b6ec320b298d6fd9a827ac7e327f99905ce80 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Sun, 1 Nov 2026 23:11:55 +0800 Subject: [PATCH 15/33] refactor: add cell-independent SNAP contribution accumulator --- .../source_md/module_snap/snap_calculator.cpp | 69 +++++++++++++++++++ .../source_md/module_snap/snap_calculator.h | 21 ++++++ .../unittest/test_snap_calculator.cpp | 24 +++---- 3 files changed, 98 insertions(+), 16 deletions(-) diff --git a/source/source_md/module_snap/snap_calculator.cpp b/source/source_md/module_snap/snap_calculator.cpp index 6c8b8bec22b..5e33e78094d 100644 --- a/source/source_md/module_snap/snap_calculator.cpp +++ b/source/source_md/module_snap/snap_calculator.cpp @@ -171,5 +171,74 @@ ForceResult Calculator::compute_with_finite_difference_force(const std::vector& neighbor_indices, + const std::vector& neighbors, + const ForceResult& result) +{ + if (center_index >= forces_.size() || neighbor_indices.size() != neighbors.size() + || result.neighbor_forces.size() != neighbors.size() || result.center_force.size() != 3) + { + throw std::invalid_argument("SNAP cell contribution has inconsistent atom or force indices."); + } + for (std::size_t index = 0; index < neighbor_indices.size(); ++index) + { + if (neighbor_indices[index] >= forces_.size() || result.neighbor_forces[index].size() != 3) + { + throw std::invalid_argument("SNAP neighbor force index is outside the cell."); + } + } + + energy_ += result.energy.energy; + for (int direction = 0; direction < 3; ++direction) + { + forces_[center_index][static_cast(direction)] += + result.center_force[static_cast(direction)]; + } + for (std::size_t index = 0; index < neighbors.size(); ++index) + { + const Neighbor& neighbor = neighbors[index]; + const double displacement[3] = {neighbor.x, neighbor.y, neighbor.z}; + const std::size_t atom = neighbor_indices[index]; + for (int direction = 0; direction < 3; ++direction) + { + forces_[atom][static_cast(direction)] += + result.neighbor_forces[index][static_cast(direction)]; + } + for (int row = 0; row < 3; ++row) + { + for (int column = 0; column < 3; ++column) + { + virial_[static_cast(3 * row + column)] += + displacement[row] * result.neighbor_forces[index][static_cast(column)]; + } + } + } +} + +double CellAccumulator::energy() const +{ + return energy_; +} + +const std::vector >& CellAccumulator::forces() const +{ + return forces_; +} + +const std::array& CellAccumulator::virial() const +{ + return virial_; +} + } // namespace SNAP } // namespace ModuleMD diff --git a/source/source_md/module_snap/snap_calculator.h b/source/source_md/module_snap/snap_calculator.h index 2eeed6b2a33..3bbc9caead9 100644 --- a/source/source_md/module_snap/snap_calculator.h +++ b/source/source_md/module_snap/snap_calculator.h @@ -4,6 +4,7 @@ #include "snap_descriptor.h" #include "snap_model.h" +#include #include namespace ModuleMD @@ -49,6 +50,26 @@ class Calculator std::size_t descriptor_size_; }; +class CellAccumulator +{ + public: + explicit CellAccumulator(std::size_t atom_count); + + void add(std::size_t center_index, + const std::vector& neighbor_indices, + const std::vector& neighbors, + const ForceResult& result); + + double energy() const; + const std::vector >& forces() const; + const std::array& virial() const; + + private: + double energy_ = 0.0; + std::vector > forces_; + std::array virial_; +}; + } // namespace SNAP } // namespace ModuleMD diff --git a/source/source_md/module_snap/unittest/test_snap_calculator.cpp b/source/source_md/module_snap/unittest/test_snap_calculator.cpp index 2cbe6c75316..33ef835cd02 100644 --- a/source/source_md/module_snap/unittest/test_snap_calculator.cpp +++ b/source/source_md/module_snap/unittest/test_snap_calculator.cpp @@ -90,6 +90,7 @@ SmallCellResult evaluate_small_cell(const ModuleMD::SNAP::Calculator& calculator const std::array, 3>& positions) { SmallCellResult total; + ModuleMD::SNAP::CellAccumulator accumulator(positions.size()); for (std::size_t center = 0; center < positions.size(); ++center) { std::vector neighbors; @@ -109,22 +110,13 @@ SmallCellResult evaluate_small_cell(const ModuleMD::SNAP::Calculator& calculator neighbor_indices.push_back(atom); } const ModuleMD::SNAP::ForceResult result = calculator.compute_with_analytic_force(neighbors, 0); - total.energy += result.energy.energy; - for (int direction = 0; direction < 3; ++direction) - { - total.forces[center][static_cast(direction)] += - result.center_force[static_cast(direction)]; - } - for (std::size_t index = 0; index < neighbors.size(); ++index) - { - const std::size_t atom = neighbor_indices[index]; - for (int direction = 0; direction < 3; ++direction) - { - total.forces[atom][static_cast(direction)] += - result.neighbor_forces[index][static_cast(direction)]; - } - total.virial_xx += neighbors[index].x * result.neighbor_forces[index][0]; - } + accumulator.add(center, neighbor_indices, neighbors, result); + } + total.energy = accumulator.energy(); + total.virial_xx = accumulator.virial()[0]; + for (std::size_t atom = 0; atom < positions.size(); ++atom) + { + total.forces[atom] = accumulator.forces()[atom]; } return total; } From 45dd06212d9212b30153e52c0dd6e4fc826dffe3 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Sun, 1 Nov 2026 23:13:51 +0800 Subject: [PATCH 16/33] refactor: use SNAP accumulator for MDCell contributions --- source/source_esolver/esolver_snap.cpp | 59 ++++++++++---------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/source/source_esolver/esolver_snap.cpp b/source/source_esolver/esolver_snap.cpp index cf5d68c81d6..f3ce506f92e 100644 --- a/source/source_esolver/esolver_snap.cpp +++ b/source/source_esolver/esolver_snap.cpp @@ -131,7 +131,7 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) const std::vector& all_atoms = mdcell.neighbor_search().get_all_atoms(); const NeighborList& list = mdcell.neighbor_search().get_neighbor_list(); const int nowned = static_cast(owned_atoms.size()); - std::vector > all_force(all_atoms.size()); + ModuleMD::SNAP::CellAccumulator contribution(all_atoms.size()); for (int i = 0; i < nowned; ++i) { const NeighborAtom center(owned_atoms[static_cast(i)].cart.x, @@ -141,6 +141,7 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) i, i); std::vector neighbors; + std::vector neighbor_indices; for (int k = 0; k < list.get_numneigh(i); ++k) { const int neighbor_index = list.get_firstneigh(i)[k]; @@ -150,54 +151,40 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) fail("MDCell atom type is outside the SNAP element map."); } neighbors.push_back(make_neighbor(center, neighbor, mdcell.lat0(), model_.parameters)); + neighbor_indices.push_back(static_cast(neighbor_index)); } - const ModuleMD::SNAP::ForceResult result = calculator_->compute_with_analytic_force( - neighbors, static_cast(center.atom_type)); - snap_potential_ += result.energy.energy / ModuleBase::Ry_to_eV; - all_force[static_cast(i)] += ModuleBase::Vector3(result.center_force[0], - result.center_force[1], - result.center_force[2]); - for (std::size_t k = 0; k < result.neighbor_forces.size(); ++k) + const std::size_t center_element = static_cast(center.atom_type); + const ModuleMD::SNAP::ForceResult result = calculator_->compute_with_analytic_force(neighbors, center_element); + const std::size_t center_index = static_cast(i); + contribution.add(center_index, neighbor_indices, neighbors, result); + } + snap_potential_ = contribution.energy() / ModuleBase::Ry_to_eV; + const double virial_scale = 1.0 / (ModuleBase::Ry_to_eV * mdcell.omega()); + for (int row = 0; row < 3; ++row) + { + for (int column = 0; column < 3; ++column) { - const int neighbor_index = list.get_firstneigh(i)[static_cast(k)]; - all_force[static_cast(neighbor_index)] += - ModuleBase::Vector3(result.neighbor_forces[k][0], - result.neighbor_forces[k][1], - result.neighbor_forces[k][2]); - const NeighborAtom& neighbor = all_atoms[static_cast(neighbor_index)]; - const double relative[3] = { - (center.position_x - neighbor.position_x) * mdcell.lat0() * ModuleBase::BOHR_TO_A, - (center.position_y - neighbor.position_y) * mdcell.lat0() * ModuleBase::BOHR_TO_A, - (center.position_z - neighbor.position_z) * mdcell.lat0() * ModuleBase::BOHR_TO_A}; - const double pair_force[3] = {-result.neighbor_forces[k][0], - -result.neighbor_forces[k][1], - -result.neighbor_forces[k][2]}; - for (int row = 0; row < 3; ++row) - { - for (int column = 0; column < 3; ++column) - { - snap_virial_(row, column) += relative[row] * pair_force[column] - / (ModuleBase::Ry_to_eV * mdcell.omega()); - } - } + const std::size_t index = static_cast(3 * row + column); + snap_virial_(row, column) = contribution.virial()[index] * virial_scale; } } const double force_scale = 1.0 / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU); for (std::size_t i = 0; i < mdcell.ghost_atoms().size(); ++i) { - const ModuleBase::Vector3& value = all_force[nowned + i]; - mdcell.ghost_atoms()[i].force.set(value.x * force_scale, - value.y * force_scale, - value.z * force_scale); + const std::array& value = contribution.forces()[nowned + i]; + mdcell.ghost_atoms()[i].force.set(value[0] * force_scale, + value[1] * force_scale, + value[2] * force_scale); } Parallel_Reduce::reduce_all(snap_potential_); Parallel_Reduce::reduce_all(snap_virial_.c, 9); for (int i = 0; i < nowned; ++i) { + const std::array& value = contribution.forces()[static_cast(i)]; owned_atoms[static_cast(i)].force.set( - all_force[static_cast(i)].x * force_scale, - all_force[static_cast(i)].y * force_scale, - all_force[static_cast(i)].z * force_scale); + value[0] * force_scale, + value[1] * force_scale, + value[2] * force_scale); } return; } From 8fbec3fa6464924dc4743320e3782f4d9f7ba04c Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Sun, 1 Nov 2026 23:17:16 +0800 Subject: [PATCH 17/33] refactor: use SNAP accumulator for UnitCell contributions --- source/source_esolver/esolver_snap.cpp | 58 ++++++++----------- .../106_SNAP_angular_quadratic_scf/INPUT | 12 ++++ .../106_SNAP_angular_quadratic_scf/README | 4 ++ .../04_FF/106_SNAP_angular_quadratic_scf/STRU | 20 +++++++ .../106_SNAP_angular_quadratic_scf/result.ref | 5 ++ .../106_SNAP_angular_quadratic_scf/snap.coeff | 24 ++++++++ .../106_SNAP_angular_quadratic_scf/snap.param | 6 ++ tests/04_FF/CASES_CPU.txt | 1 + 8 files changed, 96 insertions(+), 34 deletions(-) create mode 100644 tests/04_FF/106_SNAP_angular_quadratic_scf/INPUT create mode 100644 tests/04_FF/106_SNAP_angular_quadratic_scf/README create mode 100644 tests/04_FF/106_SNAP_angular_quadratic_scf/STRU create mode 100644 tests/04_FF/106_SNAP_angular_quadratic_scf/result.ref create mode 100644 tests/04_FF/106_SNAP_angular_quadratic_scf/snap.coeff create mode 100644 tests/04_FF/106_SNAP_angular_quadratic_scf/snap.param diff --git a/source/source_esolver/esolver_snap.cpp b/source/source_esolver/esolver_snap.cpp index f3ce506f92e..bc176ac3e8a 100644 --- a/source/source_esolver/esolver_snap.cpp +++ b/source/source_esolver/esolver_snap.cpp @@ -197,6 +197,8 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) const std::vector& inside = search.get_inside_atoms(); const std::vector& all = search.get_all_atoms(); snap_force_.zero_out(); + const std::size_t atom_count = static_cast(ucell.nat); + ModuleMD::SNAP::CellAccumulator contribution(atom_count); std::vector offsets(static_cast(ucell.ntype + 1), 0); for (int it = 0; it < ucell.ntype; ++it) { @@ -206,51 +208,39 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) { const NeighborAtom& center = inside[static_cast(local_i)]; std::vector neighbors; - std::vector atom_indices; + std::vector atom_indices; for (int k = 0; k < list.get_numneigh(local_i); ++k) { const NeighborAtom& neighbor = all[static_cast(list.get_firstneigh(local_i)[k])]; neighbors.push_back(make_neighbor(center, neighbor, ucell.lat0, model_.parameters)); - atom_indices.push_back(offsets[static_cast(neighbor.atom_type)] + neighbor.atom_index); + const int atom_index = offsets[static_cast(neighbor.atom_type)] + neighbor.atom_index; + const std::size_t index = static_cast(atom_index); + atom_indices.push_back(index); } const std::size_t center_element = static_cast(center.atom_type); const ModuleMD::SNAP::ForceResult result = calculator_->compute_with_analytic_force(neighbors, center_element); - snap_potential_ += result.energy.energy / ModuleBase::Ry_to_eV; - for (std::size_t k = 0; k < atom_indices.size(); ++k) - { - const NeighborAtom& neighbor = all[static_cast(list.get_firstneigh(local_i)[static_cast(k)])]; - const double dx = (center.position_x - neighbor.position_x) * ucell.lat0 * ModuleBase::BOHR_TO_A; - const double dy = (center.position_y - neighbor.position_y) * ucell.lat0 * ModuleBase::BOHR_TO_A; - const double dz = (center.position_z - neighbor.position_z) * ucell.lat0 * ModuleBase::BOHR_TO_A; - const double center_force_x = -result.neighbor_forces[k][0]; - const double center_force_y = -result.neighbor_forces[k][1]; - const double center_force_z = -result.neighbor_forces[k][2]; - const double relative[3] = {dx, dy, dz}; - const double pair_force[3] = {center_force_x, center_force_y, center_force_z}; - for (int row = 0; row < 3; ++row) - { - for (int column = 0; column < 3; ++column) - { - snap_virial_(row, column) += relative[row] * pair_force[column] - / (ModuleBase::Ry_to_eV * ucell.omega); - } - } - } const int center_index = offsets[static_cast(center.atom_type)] + center.atom_index; - for (int direction = 0; direction < 3; ++direction) + const std::size_t index = static_cast(center_index); + contribution.add(index, atom_indices, neighbors, result); + } + snap_potential_ = contribution.energy() / ModuleBase::Ry_to_eV; + const double virial_scale = 1.0 / (ModuleBase::Ry_to_eV * ucell.omega); + for (int row = 0; row < 3; ++row) + { + for (int column = 0; column < 3; ++column) { - snap_force_(center_index, direction) += - result.center_force[static_cast(direction)] - / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU); + const std::size_t index = static_cast(3 * row + column); + snap_virial_(row, column) = contribution.virial()[index] * virial_scale; } - for (std::size_t k = 0; k < atom_indices.size(); ++k) + } + const double force_scale = 1.0 / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU); + for (int atom_index = 0; atom_index < ucell.nat; ++atom_index) + { + for (int direction = 0; direction < 3; ++direction) { - for (int direction = 0; direction < 3; ++direction) - { - snap_force_(atom_indices[k], direction) += - result.neighbor_forces[k][static_cast(direction)] - / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU); - } + const std::size_t index = static_cast(atom_index); + const std::size_t component = static_cast(direction); + snap_force_(atom_index, direction) = contribution.forces()[index][component] * force_scale; } } } diff --git a/tests/04_FF/106_SNAP_angular_quadratic_scf/INPUT b/tests/04_FF/106_SNAP_angular_quadratic_scf/INPUT new file mode 100644 index 00000000000..4bf5f37ee32 --- /dev/null +++ b/tests/04_FF/106_SNAP_angular_quadratic_scf/INPUT @@ -0,0 +1,12 @@ +INPUT_PARAMETERS +calculation scf +suffix autotest +esolver_type snap +pot_file snap.coeff +snap_param_file snap.param +cal_force 1 +cal_stress 1 +md_nstep 1 +md_type nve +md_dt 1 +init_vel 0 diff --git a/tests/04_FF/106_SNAP_angular_quadratic_scf/README b/tests/04_FF/106_SNAP_angular_quadratic_scf/README new file mode 100644 index 00000000000..0bc0b1ac1aa --- /dev/null +++ b/tests/04_FF/106_SNAP_angular_quadratic_scf/README @@ -0,0 +1,4 @@ +UnitCell SNAP single-point regression using the same angular and quadratic +model as case 105. The calculation enters the UnitCell solver path rather +than the direct MDCell path. Energy, total force, and stress must match case +105 and the LAMMPS reference described there. diff --git a/tests/04_FF/106_SNAP_angular_quadratic_scf/STRU b/tests/04_FF/106_SNAP_angular_quadratic_scf/STRU new file mode 100644 index 00000000000..8a6eaca3fb4 --- /dev/null +++ b/tests/04_FF/106_SNAP_angular_quadratic_scf/STRU @@ -0,0 +1,20 @@ +ATOMIC_SPECIES +Si 28.0855 auto auto + +LATTICE_CONSTANT +1.0 + +LATTICE_VECTORS +20.0 0.0 0.0 +0.0 20.0 0.0 +0.0 0.0 20.0 + +ATOMIC_POSITIONS +Cartesian + +Si +0 +3 +0.0 0.0 0.0 m 1 1 1 +2.0 0.0 0.0 m 1 1 1 +0.5 2.5 0.0 m 1 1 1 diff --git a/tests/04_FF/106_SNAP_angular_quadratic_scf/result.ref b/tests/04_FF/106_SNAP_angular_quadratic_scf/result.ref new file mode 100644 index 00000000000..c7bd38b168d --- /dev/null +++ b/tests/04_FF/106_SNAP_angular_quadratic_scf/result.ref @@ -0,0 +1,5 @@ +etotref 54.909561 +etotperatomref 18.3031870000 +totalforceref 420.564050 +totalstressref 422.994068 +totaltimeref 0.02 diff --git a/tests/04_FF/106_SNAP_angular_quadratic_scf/snap.coeff b/tests/04_FF/106_SNAP_angular_quadratic_scf/snap.coeff new file mode 100644 index 00000000000..aa7b790cd3f --- /dev/null +++ b/tests/04_FF/106_SNAP_angular_quadratic_scf/snap.coeff @@ -0,0 +1,24 @@ +# Deterministic software-test coefficients for angular and quadratic SNAP. +1 21 +Si 2.25 1.0 +0.2 +0.3 +-0.1 +0.5 +0.2 +-0.4 +0.25 +0.0 +0.0 +0.0 +-0.15 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 diff --git a/tests/04_FF/106_SNAP_angular_quadratic_scf/snap.param b/tests/04_FF/106_SNAP_angular_quadratic_scf/snap.param new file mode 100644 index 00000000000..eebdca8cf58 --- /dev/null +++ b/tests/04_FF/106_SNAP_angular_quadratic_scf/snap.param @@ -0,0 +1,6 @@ +rcutfac 1.0 +twojmax 2 +rfac0 0.99363 +rmin0 0.0 +quadraticflag 1 +bzeroflag 1 diff --git a/tests/04_FF/CASES_CPU.txt b/tests/04_FF/CASES_CPU.txt index f439e013927..708ff953c59 100644 --- a/tests/04_FF/CASES_CPU.txt +++ b/tests/04_FF/CASES_CPU.txt @@ -24,3 +24,4 @@ 103_SNAP_periodic 104_SNAP_inner 105_SNAP_angular_quadratic +106_SNAP_angular_quadratic_scf From 68d55754f78d3f9bb8ea69f86ac5d95a4cecd5e5 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 13:22:26 +0800 Subject: [PATCH 18/33] refactor: centralize SNAP regression models and test layout --- source/source_md/module_snap/CMakeLists.txt | 2 +- .../{unittest => unittests}/CMakeLists.txt | 0 .../test_snap_calculator.cpp | 0 .../test_snap_clebsch_gordan.cpp | 0 .../test_snap_descriptor.cpp | 0 .../test_snap_model.cpp | 0 .../{102_SNAP_minimal => 102_SNAP_base}/INPUT | 4 +- .../README | 2 +- .../{102_SNAP_minimal => 102_SNAP_base}/STRU | 0 .../result.ref | 0 .../INPUT | 4 +- .../README | 2 +- .../{103_SNAP_periodic => 103_SNAP_pbc}/STRU | 0 .../result.ref | 0 tests/04_FF/103_SNAP_periodic/snap.coeff | 62 ------------------- tests/04_FF/103_SNAP_periodic/snap.param | 10 --- tests/04_FF/104_SNAP_inner/INPUT | 4 +- tests/04_FF/104_SNAP_inner/snap.coeff | 62 ------------------- .../INPUT | 4 +- .../README | 0 .../STRU | 0 .../result.ref | 0 .../106_SNAP_angular_quadratic_scf/snap.coeff | 24 ------- .../106_SNAP_angular_quadratic_scf/snap.param | 6 -- .../INPUT | 4 +- .../README | 0 .../STRU | 0 .../result.ref | 0 tests/04_FF/CASES_CPU.txt | 8 +-- .../snap1.coeff} | 0 .../snap1.param} | 0 .../snap2.param} | 0 .../snap3.coeff} | 0 .../snap3.param} | 0 34 files changed, 17 insertions(+), 181 deletions(-) rename source/source_md/module_snap/{unittest => unittests}/CMakeLists.txt (100%) rename source/source_md/module_snap/{unittest => unittests}/test_snap_calculator.cpp (100%) rename source/source_md/module_snap/{unittest => unittests}/test_snap_clebsch_gordan.cpp (100%) rename source/source_md/module_snap/{unittest => unittests}/test_snap_descriptor.cpp (100%) rename source/source_md/module_snap/{unittest => unittests}/test_snap_model.cpp (100%) rename tests/04_FF/{102_SNAP_minimal => 102_SNAP_base}/INPUT (66%) rename tests/04_FF/{102_SNAP_minimal => 102_SNAP_base}/README (81%) rename tests/04_FF/{102_SNAP_minimal => 102_SNAP_base}/STRU (100%) rename tests/04_FF/{102_SNAP_minimal => 102_SNAP_base}/result.ref (100%) rename tests/04_FF/{105_SNAP_angular_quadratic => 103_SNAP_pbc}/INPUT (66%) rename tests/04_FF/{103_SNAP_periodic => 103_SNAP_pbc}/README (96%) rename tests/04_FF/{103_SNAP_periodic => 103_SNAP_pbc}/STRU (100%) rename tests/04_FF/{103_SNAP_periodic => 103_SNAP_pbc}/result.ref (100%) delete mode 100644 tests/04_FF/103_SNAP_periodic/snap.coeff delete mode 100644 tests/04_FF/103_SNAP_periodic/snap.param delete mode 100644 tests/04_FF/104_SNAP_inner/snap.coeff rename tests/04_FF/{103_SNAP_periodic => 105_SNAP_quad}/INPUT (66%) rename tests/04_FF/{105_SNAP_angular_quadratic => 105_SNAP_quad}/README (100%) rename tests/04_FF/{105_SNAP_angular_quadratic => 105_SNAP_quad}/STRU (100%) rename tests/04_FF/{105_SNAP_angular_quadratic => 105_SNAP_quad}/result.ref (100%) delete mode 100644 tests/04_FF/106_SNAP_angular_quadratic_scf/snap.coeff delete mode 100644 tests/04_FF/106_SNAP_angular_quadratic_scf/snap.param rename tests/04_FF/{106_SNAP_angular_quadratic_scf => 106_SNAP_scf}/INPUT (66%) rename tests/04_FF/{106_SNAP_angular_quadratic_scf => 106_SNAP_scf}/README (100%) rename tests/04_FF/{106_SNAP_angular_quadratic_scf => 106_SNAP_scf}/STRU (100%) rename tests/04_FF/{106_SNAP_angular_quadratic_scf => 106_SNAP_scf}/result.ref (100%) rename tests/{04_FF/102_SNAP_minimal/snap.coeff => SIMULATION_MODELS/snap1.coeff} (100%) rename tests/{04_FF/102_SNAP_minimal/snap.param => SIMULATION_MODELS/snap1.param} (100%) rename tests/{04_FF/104_SNAP_inner/snap.param => SIMULATION_MODELS/snap2.param} (100%) rename tests/{04_FF/105_SNAP_angular_quadratic/snap.coeff => SIMULATION_MODELS/snap3.coeff} (100%) rename tests/{04_FF/105_SNAP_angular_quadratic/snap.param => SIMULATION_MODELS/snap3.param} (100%) diff --git a/source/source_md/module_snap/CMakeLists.txt b/source/source_md/module_snap/CMakeLists.txt index 3a3a8f7ec7e..2c1a032a19f 100644 --- a/source/source_md/module_snap/CMakeLists.txt +++ b/source/source_md/module_snap/CMakeLists.txt @@ -9,5 +9,5 @@ target_sources( ) if(BUILD_TESTING) - add_subdirectory(unittest) + add_subdirectory(unittests) endif() diff --git a/source/source_md/module_snap/unittest/CMakeLists.txt b/source/source_md/module_snap/unittests/CMakeLists.txt similarity index 100% rename from source/source_md/module_snap/unittest/CMakeLists.txt rename to source/source_md/module_snap/unittests/CMakeLists.txt diff --git a/source/source_md/module_snap/unittest/test_snap_calculator.cpp b/source/source_md/module_snap/unittests/test_snap_calculator.cpp similarity index 100% rename from source/source_md/module_snap/unittest/test_snap_calculator.cpp rename to source/source_md/module_snap/unittests/test_snap_calculator.cpp diff --git a/source/source_md/module_snap/unittest/test_snap_clebsch_gordan.cpp b/source/source_md/module_snap/unittests/test_snap_clebsch_gordan.cpp similarity index 100% rename from source/source_md/module_snap/unittest/test_snap_clebsch_gordan.cpp rename to source/source_md/module_snap/unittests/test_snap_clebsch_gordan.cpp diff --git a/source/source_md/module_snap/unittest/test_snap_descriptor.cpp b/source/source_md/module_snap/unittests/test_snap_descriptor.cpp similarity index 100% rename from source/source_md/module_snap/unittest/test_snap_descriptor.cpp rename to source/source_md/module_snap/unittests/test_snap_descriptor.cpp diff --git a/source/source_md/module_snap/unittest/test_snap_model.cpp b/source/source_md/module_snap/unittests/test_snap_model.cpp similarity index 100% rename from source/source_md/module_snap/unittest/test_snap_model.cpp rename to source/source_md/module_snap/unittests/test_snap_model.cpp diff --git a/tests/04_FF/102_SNAP_minimal/INPUT b/tests/04_FF/102_SNAP_base/INPUT similarity index 66% rename from tests/04_FF/102_SNAP_minimal/INPUT rename to tests/04_FF/102_SNAP_base/INPUT index 0ed0eb5b3ab..7d3649f6962 100644 --- a/tests/04_FF/102_SNAP_minimal/INPUT +++ b/tests/04_FF/102_SNAP_base/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file snap.coeff -snap_param_file snap.param +pot_file ../../SIMULATION_MODELS/snap1.coeff +snap_param_file ../../SIMULATION_MODELS/snap1.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/102_SNAP_minimal/README b/tests/04_FF/102_SNAP_base/README similarity index 81% rename from tests/04_FF/102_SNAP_minimal/README rename to tests/04_FF/102_SNAP_base/README index 26ce3c2fdea..4038675f701 100644 --- a/tests/04_FF/102_SNAP_minimal/README +++ b/tests/04_FF/102_SNAP_base/README @@ -1,6 +1,6 @@ CPU SNAP regression case with a two-atom Si periodic structure. -The example uses `snap.coeff` for the SNAP coefficients and `snap.param` for +The example uses `../../SIMULATION_MODELS/snap1.coeff` for the SNAP coefficients and `../../SIMULATION_MODELS/snap1.param` for the SNAP parameters. The coefficient and parameter files are deterministic ABACUS-generated test diff --git a/tests/04_FF/102_SNAP_minimal/STRU b/tests/04_FF/102_SNAP_base/STRU similarity index 100% rename from tests/04_FF/102_SNAP_minimal/STRU rename to tests/04_FF/102_SNAP_base/STRU diff --git a/tests/04_FF/102_SNAP_minimal/result.ref b/tests/04_FF/102_SNAP_base/result.ref similarity index 100% rename from tests/04_FF/102_SNAP_minimal/result.ref rename to tests/04_FF/102_SNAP_base/result.ref diff --git a/tests/04_FF/105_SNAP_angular_quadratic/INPUT b/tests/04_FF/103_SNAP_pbc/INPUT similarity index 66% rename from tests/04_FF/105_SNAP_angular_quadratic/INPUT rename to tests/04_FF/103_SNAP_pbc/INPUT index 0ed0eb5b3ab..7d3649f6962 100644 --- a/tests/04_FF/105_SNAP_angular_quadratic/INPUT +++ b/tests/04_FF/103_SNAP_pbc/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file snap.coeff -snap_param_file snap.param +pot_file ../../SIMULATION_MODELS/snap1.coeff +snap_param_file ../../SIMULATION_MODELS/snap1.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/103_SNAP_periodic/README b/tests/04_FF/103_SNAP_pbc/README similarity index 96% rename from tests/04_FF/103_SNAP_periodic/README rename to tests/04_FF/103_SNAP_pbc/README index 0f19eccb7bf..1d835070432 100644 --- a/tests/04_FF/103_SNAP_periodic/README +++ b/tests/04_FF/103_SNAP_pbc/README @@ -1,6 +1,6 @@ CPU SNAP periodic-image regression case. -This uses the same potential and two-atom separation as 102_SNAP_minimal, +This uses the same potential and two-atom separation as 102_SNAP_base, but places the atoms on opposite sides of the periodic boundary. Their energy, force magnitude, and stress must match the unwrapped case. The periodic neighbor contributes through the MDCell ghost-force return path. diff --git a/tests/04_FF/103_SNAP_periodic/STRU b/tests/04_FF/103_SNAP_pbc/STRU similarity index 100% rename from tests/04_FF/103_SNAP_periodic/STRU rename to tests/04_FF/103_SNAP_pbc/STRU diff --git a/tests/04_FF/103_SNAP_periodic/result.ref b/tests/04_FF/103_SNAP_pbc/result.ref similarity index 100% rename from tests/04_FF/103_SNAP_periodic/result.ref rename to tests/04_FF/103_SNAP_pbc/result.ref diff --git a/tests/04_FF/103_SNAP_periodic/snap.coeff b/tests/04_FF/103_SNAP_periodic/snap.coeff deleted file mode 100644 index fc13f2f7b43..00000000000 --- a/tests/04_FF/103_SNAP_periodic/snap.coeff +++ /dev/null @@ -1,62 +0,0 @@ -# ABACUS-generated SNAP regression fixture -# This deterministic coefficient set is created for software testing only. -# It is not a transferable or physically validated material potential. - -1 56 -Si 0.5 1 -0.125000000000 --0.002000000000 -0.003000000000 --0.004000000000 -0.005000000000 --0.006000000000 -0.007000000000 --0.008000000000 -0.009000000000 --0.010000000000 -0.011000000000 --0.012000000000 -0.013000000000 --0.014000000000 -0.015000000000 --0.016000000000 -0.017000000000 --0.018000000000 -0.019000000000 --0.020000000000 -0.021000000000 --0.022000000000 -0.023000000000 --0.024000000000 -0.025000000000 --0.026000000000 -0.027000000000 --0.028000000000 -0.029000000000 --0.030000000000 -0.031000000000 --0.032000000000 -0.033000000000 --0.034000000000 -0.035000000000 --0.036000000000 -0.037000000000 --0.038000000000 -0.039000000000 --0.040000000000 -0.041000000000 --0.042000000000 -0.043000000000 --0.044000000000 -0.045000000000 --0.046000000000 -0.047000000000 --0.048000000000 -0.049000000000 --0.050000000000 -0.051000000000 --0.052000000000 -0.053000000000 --0.054000000000 -0.055000000000 --0.056000000000 diff --git a/tests/04_FF/103_SNAP_periodic/snap.param b/tests/04_FF/103_SNAP_periodic/snap.param deleted file mode 100644 index 23e0d83d38b..00000000000 --- a/tests/04_FF/103_SNAP_periodic/snap.param +++ /dev/null @@ -1,10 +0,0 @@ -# ABACUS-generated SNAP regression fixture -# This deterministic parameter set is created for software testing only. -# It is not a transferable or physically validated material potential. - -rcutfac 4.9 -twojmax 8 -rfac0 0.99363 -rmin0 0 -quadraticflag 0 -bzeroflag 0 diff --git a/tests/04_FF/104_SNAP_inner/INPUT b/tests/04_FF/104_SNAP_inner/INPUT index 0ed0eb5b3ab..93c3bd9f381 100644 --- a/tests/04_FF/104_SNAP_inner/INPUT +++ b/tests/04_FF/104_SNAP_inner/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file snap.coeff -snap_param_file snap.param +pot_file ../../SIMULATION_MODELS/snap1.coeff +snap_param_file ../../SIMULATION_MODELS/snap2.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/104_SNAP_inner/snap.coeff b/tests/04_FF/104_SNAP_inner/snap.coeff deleted file mode 100644 index fc13f2f7b43..00000000000 --- a/tests/04_FF/104_SNAP_inner/snap.coeff +++ /dev/null @@ -1,62 +0,0 @@ -# ABACUS-generated SNAP regression fixture -# This deterministic coefficient set is created for software testing only. -# It is not a transferable or physically validated material potential. - -1 56 -Si 0.5 1 -0.125000000000 --0.002000000000 -0.003000000000 --0.004000000000 -0.005000000000 --0.006000000000 -0.007000000000 --0.008000000000 -0.009000000000 --0.010000000000 -0.011000000000 --0.012000000000 -0.013000000000 --0.014000000000 -0.015000000000 --0.016000000000 -0.017000000000 --0.018000000000 -0.019000000000 --0.020000000000 -0.021000000000 --0.022000000000 -0.023000000000 --0.024000000000 -0.025000000000 --0.026000000000 -0.027000000000 --0.028000000000 -0.029000000000 --0.030000000000 -0.031000000000 --0.032000000000 -0.033000000000 --0.034000000000 -0.035000000000 --0.036000000000 -0.037000000000 --0.038000000000 -0.039000000000 --0.040000000000 -0.041000000000 --0.042000000000 -0.043000000000 --0.044000000000 -0.045000000000 --0.046000000000 -0.047000000000 --0.048000000000 -0.049000000000 --0.050000000000 -0.051000000000 --0.052000000000 -0.053000000000 --0.054000000000 -0.055000000000 --0.056000000000 diff --git a/tests/04_FF/103_SNAP_periodic/INPUT b/tests/04_FF/105_SNAP_quad/INPUT similarity index 66% rename from tests/04_FF/103_SNAP_periodic/INPUT rename to tests/04_FF/105_SNAP_quad/INPUT index 0ed0eb5b3ab..dfa30068bed 100644 --- a/tests/04_FF/103_SNAP_periodic/INPUT +++ b/tests/04_FF/105_SNAP_quad/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file snap.coeff -snap_param_file snap.param +pot_file ../../SIMULATION_MODELS/snap3.coeff +snap_param_file ../../SIMULATION_MODELS/snap3.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/105_SNAP_angular_quadratic/README b/tests/04_FF/105_SNAP_quad/README similarity index 100% rename from tests/04_FF/105_SNAP_angular_quadratic/README rename to tests/04_FF/105_SNAP_quad/README diff --git a/tests/04_FF/105_SNAP_angular_quadratic/STRU b/tests/04_FF/105_SNAP_quad/STRU similarity index 100% rename from tests/04_FF/105_SNAP_angular_quadratic/STRU rename to tests/04_FF/105_SNAP_quad/STRU diff --git a/tests/04_FF/105_SNAP_angular_quadratic/result.ref b/tests/04_FF/105_SNAP_quad/result.ref similarity index 100% rename from tests/04_FF/105_SNAP_angular_quadratic/result.ref rename to tests/04_FF/105_SNAP_quad/result.ref diff --git a/tests/04_FF/106_SNAP_angular_quadratic_scf/snap.coeff b/tests/04_FF/106_SNAP_angular_quadratic_scf/snap.coeff deleted file mode 100644 index aa7b790cd3f..00000000000 --- a/tests/04_FF/106_SNAP_angular_quadratic_scf/snap.coeff +++ /dev/null @@ -1,24 +0,0 @@ -# Deterministic software-test coefficients for angular and quadratic SNAP. -1 21 -Si 2.25 1.0 -0.2 -0.3 --0.1 -0.5 -0.2 --0.4 -0.25 -0.0 -0.0 -0.0 --0.15 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 diff --git a/tests/04_FF/106_SNAP_angular_quadratic_scf/snap.param b/tests/04_FF/106_SNAP_angular_quadratic_scf/snap.param deleted file mode 100644 index eebdca8cf58..00000000000 --- a/tests/04_FF/106_SNAP_angular_quadratic_scf/snap.param +++ /dev/null @@ -1,6 +0,0 @@ -rcutfac 1.0 -twojmax 2 -rfac0 0.99363 -rmin0 0.0 -quadraticflag 1 -bzeroflag 1 diff --git a/tests/04_FF/106_SNAP_angular_quadratic_scf/INPUT b/tests/04_FF/106_SNAP_scf/INPUT similarity index 66% rename from tests/04_FF/106_SNAP_angular_quadratic_scf/INPUT rename to tests/04_FF/106_SNAP_scf/INPUT index 4bf5f37ee32..52fca03b771 100644 --- a/tests/04_FF/106_SNAP_angular_quadratic_scf/INPUT +++ b/tests/04_FF/106_SNAP_scf/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation scf suffix autotest esolver_type snap -pot_file snap.coeff -snap_param_file snap.param +pot_file ../../SIMULATION_MODELS/snap3.coeff +snap_param_file ../../SIMULATION_MODELS/snap3.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/106_SNAP_angular_quadratic_scf/README b/tests/04_FF/106_SNAP_scf/README similarity index 100% rename from tests/04_FF/106_SNAP_angular_quadratic_scf/README rename to tests/04_FF/106_SNAP_scf/README diff --git a/tests/04_FF/106_SNAP_angular_quadratic_scf/STRU b/tests/04_FF/106_SNAP_scf/STRU similarity index 100% rename from tests/04_FF/106_SNAP_angular_quadratic_scf/STRU rename to tests/04_FF/106_SNAP_scf/STRU diff --git a/tests/04_FF/106_SNAP_angular_quadratic_scf/result.ref b/tests/04_FF/106_SNAP_scf/result.ref similarity index 100% rename from tests/04_FF/106_SNAP_angular_quadratic_scf/result.ref rename to tests/04_FF/106_SNAP_scf/result.ref diff --git a/tests/04_FF/CASES_CPU.txt b/tests/04_FF/CASES_CPU.txt index 708ff953c59..4f66a60ae0a 100644 --- a/tests/04_FF/CASES_CPU.txt +++ b/tests/04_FF/CASES_CPU.txt @@ -20,8 +20,8 @@ 20_LJ_dry_run #50_DP_Al #101_NEP_HfO2 -102_SNAP_minimal -103_SNAP_periodic +102_SNAP_base +103_SNAP_pbc 104_SNAP_inner -105_SNAP_angular_quadratic -106_SNAP_angular_quadratic_scf +105_SNAP_quad +106_SNAP_scf diff --git a/tests/04_FF/102_SNAP_minimal/snap.coeff b/tests/SIMULATION_MODELS/snap1.coeff similarity index 100% rename from tests/04_FF/102_SNAP_minimal/snap.coeff rename to tests/SIMULATION_MODELS/snap1.coeff diff --git a/tests/04_FF/102_SNAP_minimal/snap.param b/tests/SIMULATION_MODELS/snap1.param similarity index 100% rename from tests/04_FF/102_SNAP_minimal/snap.param rename to tests/SIMULATION_MODELS/snap1.param diff --git a/tests/04_FF/104_SNAP_inner/snap.param b/tests/SIMULATION_MODELS/snap2.param similarity index 100% rename from tests/04_FF/104_SNAP_inner/snap.param rename to tests/SIMULATION_MODELS/snap2.param diff --git a/tests/04_FF/105_SNAP_angular_quadratic/snap.coeff b/tests/SIMULATION_MODELS/snap3.coeff similarity index 100% rename from tests/04_FF/105_SNAP_angular_quadratic/snap.coeff rename to tests/SIMULATION_MODELS/snap3.coeff diff --git a/tests/04_FF/105_SNAP_angular_quadratic/snap.param b/tests/SIMULATION_MODELS/snap3.param similarity index 100% rename from tests/04_FF/105_SNAP_angular_quadratic/snap.param rename to tests/SIMULATION_MODELS/snap3.param From be7660a02a4503d6a6d61fd38af6384cdf48ae3f Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 13:23:17 +0800 Subject: [PATCH 19/33] refactor: shorten SNAP source and test file names --- source/Makefile.Objects | 12 ++++++------ source/source_esolver/CMakeLists.txt | 2 +- source/source_esolver/esolver_factory.cpp | 2 +- .../{esolver_snap.cpp => snap_solver.cpp} | 2 +- .../source_esolver/{esolver_snap.h => snap_solver.h} | 2 +- source/source_md/module_snap/CMakeLists.txt | 10 +++++----- .../module_snap/{snap_calculator.cpp => calc.cpp} | 2 +- .../module_snap/{snap_calculator.h => calc.h} | 4 ++-- .../module_snap/{snap_clebsch_gordan.cpp => cg.cpp} | 2 +- .../module_snap/{snap_clebsch_gordan.h => cg.h} | 0 .../{snap_descriptor_derivative.cpp => deriv.cpp} | 2 +- .../module_snap/{snap_descriptor.cpp => desc.cpp} | 2 +- .../module_snap/{snap_descriptor.h => desc.h} | 4 ++-- .../module_snap/{snap_model.cpp => model.cpp} | 2 +- .../source_md/module_snap/{snap_model.h => model.h} | 0 .../source_md/module_snap/unittests/CMakeLists.txt | 8 ++++---- .../{test_snap_calculator.cpp => test_calc.cpp} | 2 +- .../{test_snap_clebsch_gordan.cpp => test_cg.cpp} | 2 +- .../{test_snap_descriptor.cpp => test_desc.cpp} | 2 +- .../{test_snap_model.cpp => test_model.cpp} | 2 +- 20 files changed, 32 insertions(+), 32 deletions(-) rename source/source_esolver/{esolver_snap.cpp => snap_solver.cpp} (99%) rename source/source_esolver/{esolver_snap.h => snap_solver.h} (95%) rename source/source_md/module_snap/{snap_calculator.cpp => calc.cpp} (99%) rename source/source_md/module_snap/{snap_calculator.h => calc.h} (97%) rename source/source_md/module_snap/{snap_clebsch_gordan.cpp => cg.cpp} (99%) rename source/source_md/module_snap/{snap_clebsch_gordan.h => cg.h} (100%) rename source/source_md/module_snap/{snap_descriptor_derivative.cpp => deriv.cpp} (99%) rename source/source_md/module_snap/{snap_descriptor.cpp => desc.cpp} (99%) rename source/source_md/module_snap/{snap_descriptor.h => desc.h} (97%) rename source/source_md/module_snap/{snap_model.cpp => model.cpp} (99%) rename source/source_md/module_snap/{snap_model.h => model.h} (100%) rename source/source_md/module_snap/unittests/{test_snap_calculator.cpp => test_calc.cpp} (99%) rename source/source_md/module_snap/unittests/{test_snap_clebsch_gordan.cpp => test_cg.cpp} (96%) rename source/source_md/module_snap/unittests/{test_snap_descriptor.cpp => test_desc.cpp} (99%) rename source/source_md/module_snap/unittests/{test_snap_model.cpp => test_model.cpp} (99%) diff --git a/source/Makefile.Objects b/source/Makefile.Objects index d61284f431c..f4ac6ec707c 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -337,7 +337,7 @@ OBJS_ESOLVER=esolver_factory.o\ esolver_lj.o\ esolver_dp.o\ esolver_nep.o\ - esolver_snap.o\ + snap_solver.o\ esolver_of.o\ esolver_of_tddft.o\ esolver_of_interface.o\ @@ -538,11 +538,11 @@ OBJS_MD=fire.o\ nhchain.o\ plumed_interface.o\ run_md.o\ - module_snap/snap_calculator.o\ - module_snap/snap_descriptor.o\ - module_snap/snap_descriptor_derivative.o\ - module_snap/snap_model.o\ - module_snap/snap_clebsch_gordan.o\ + module_snap/calc.o\ + module_snap/desc.o\ + module_snap/deriv.o\ + module_snap/model.o\ + module_snap/cg.o\ verlet.o\ OBJS_NEIGHBOR=sltk_atom.o\ diff --git a/source/source_esolver/CMakeLists.txt b/source/source_esolver/CMakeLists.txt index 3ccfe94f3bd..5cd61aceb5d 100644 --- a/source/source_esolver/CMakeLists.txt +++ b/source/source_esolver/CMakeLists.txt @@ -9,7 +9,7 @@ list(APPEND objects esolver_lj.cpp esolver_dp.cpp esolver_nep.cpp - esolver_snap.cpp + snap_solver.cpp esolver_of.cpp esolver_of_tddft.cpp esolver_of_interface.cpp diff --git a/source/source_esolver/esolver_factory.cpp b/source/source_esolver/esolver_factory.cpp index d69af4ac73a..76c4e2b0fc8 100644 --- a/source/source_esolver/esolver_factory.cpp +++ b/source/source_esolver/esolver_factory.cpp @@ -24,7 +24,7 @@ #endif #include "esolver_dp.h" #include "esolver_nep.h" -#include "esolver_snap.h" +#include "snap_solver.h" #include "esolver_lj.h" #include "esolver_of.h" #include "esolver_of_tddft.h" diff --git a/source/source_esolver/esolver_snap.cpp b/source/source_esolver/snap_solver.cpp similarity index 99% rename from source/source_esolver/esolver_snap.cpp rename to source/source_esolver/snap_solver.cpp index bc176ac3e8a..8fe03475504 100644 --- a/source/source_esolver/esolver_snap.cpp +++ b/source/source_esolver/snap_solver.cpp @@ -1,4 +1,4 @@ -#include "esolver_snap.h" +#include "snap_solver.h" #include "source_base/constants.h" #include "source_base/global_variable.h" diff --git a/source/source_esolver/esolver_snap.h b/source/source_esolver/snap_solver.h similarity index 95% rename from source/source_esolver/esolver_snap.h rename to source/source_esolver/snap_solver.h index cad1b79af4a..fd95047305a 100644 --- a/source/source_esolver/esolver_snap.h +++ b/source/source_esolver/snap_solver.h @@ -2,7 +2,7 @@ #define ESOLVER_SNAP_H #include "esolver.h" -#include "source_md/module_snap/snap_calculator.h" +#include "source_md/module_snap/calc.h" #include #include diff --git a/source/source_md/module_snap/CMakeLists.txt b/source/source_md/module_snap/CMakeLists.txt index 2c1a032a19f..3a427947a6a 100644 --- a/source/source_md/module_snap/CMakeLists.txt +++ b/source/source_md/module_snap/CMakeLists.txt @@ -1,11 +1,11 @@ target_sources( md PRIVATE - snap_calculator.cpp - snap_descriptor.cpp - snap_descriptor_derivative.cpp - snap_model.cpp - snap_clebsch_gordan.cpp + calc.cpp + desc.cpp + deriv.cpp + model.cpp + cg.cpp ) if(BUILD_TESTING) diff --git a/source/source_md/module_snap/snap_calculator.cpp b/source/source_md/module_snap/calc.cpp similarity index 99% rename from source/source_md/module_snap/snap_calculator.cpp rename to source/source_md/module_snap/calc.cpp index 5e33e78094d..4fedbd3a66a 100644 --- a/source/source_md/module_snap/snap_calculator.cpp +++ b/source/source_md/module_snap/calc.cpp @@ -1,4 +1,4 @@ -#include "snap_calculator.h" +#include "calc.h" #include diff --git a/source/source_md/module_snap/snap_calculator.h b/source/source_md/module_snap/calc.h similarity index 97% rename from source/source_md/module_snap/snap_calculator.h rename to source/source_md/module_snap/calc.h index 3bbc9caead9..92b2a745910 100644 --- a/source/source_md/module_snap/snap_calculator.h +++ b/source/source_md/module_snap/calc.h @@ -1,8 +1,8 @@ #ifndef SNAP_CALCULATOR_H #define SNAP_CALCULATOR_H -#include "snap_descriptor.h" -#include "snap_model.h" +#include "desc.h" +#include "model.h" #include #include diff --git a/source/source_md/module_snap/snap_clebsch_gordan.cpp b/source/source_md/module_snap/cg.cpp similarity index 99% rename from source/source_md/module_snap/snap_clebsch_gordan.cpp rename to source/source_md/module_snap/cg.cpp index f2d65865662..79404bff331 100644 --- a/source/source_md/module_snap/snap_clebsch_gordan.cpp +++ b/source/source_md/module_snap/cg.cpp @@ -1,4 +1,4 @@ -#include "snap_clebsch_gordan.h" +#include "cg.h" #include diff --git a/source/source_md/module_snap/snap_clebsch_gordan.h b/source/source_md/module_snap/cg.h similarity index 100% rename from source/source_md/module_snap/snap_clebsch_gordan.h rename to source/source_md/module_snap/cg.h diff --git a/source/source_md/module_snap/snap_descriptor_derivative.cpp b/source/source_md/module_snap/deriv.cpp similarity index 99% rename from source/source_md/module_snap/snap_descriptor_derivative.cpp rename to source/source_md/module_snap/deriv.cpp index cea61b8a31b..e59f35a5eb3 100644 --- a/source/source_md/module_snap/snap_descriptor_derivative.cpp +++ b/source/source_md/module_snap/deriv.cpp @@ -1,4 +1,4 @@ -#include "snap_descriptor.h" +#include "desc.h" #include "source_base/constants.h" diff --git a/source/source_md/module_snap/snap_descriptor.cpp b/source/source_md/module_snap/desc.cpp similarity index 99% rename from source/source_md/module_snap/snap_descriptor.cpp rename to source/source_md/module_snap/desc.cpp index a0c33db3b64..42e65f294a2 100644 --- a/source/source_md/module_snap/snap_descriptor.cpp +++ b/source/source_md/module_snap/desc.cpp @@ -1,4 +1,4 @@ -#include "snap_descriptor.h" +#include "desc.h" #include "source_base/constants.h" diff --git a/source/source_md/module_snap/snap_descriptor.h b/source/source_md/module_snap/desc.h similarity index 97% rename from source/source_md/module_snap/snap_descriptor.h rename to source/source_md/module_snap/desc.h index a20f495bac4..367ca1115ac 100644 --- a/source/source_md/module_snap/snap_descriptor.h +++ b/source/source_md/module_snap/desc.h @@ -1,8 +1,8 @@ #ifndef SNAP_DESCRIPTOR_H #define SNAP_DESCRIPTOR_H -#include "snap_clebsch_gordan.h" -#include "snap_model.h" +#include "cg.h" +#include "model.h" #include #include diff --git a/source/source_md/module_snap/snap_model.cpp b/source/source_md/module_snap/model.cpp similarity index 99% rename from source/source_md/module_snap/snap_model.cpp rename to source/source_md/module_snap/model.cpp index 6df5673d859..bf7cfb41ae9 100644 --- a/source/source_md/module_snap/snap_model.cpp +++ b/source/source_md/module_snap/model.cpp @@ -1,4 +1,4 @@ -#include "snap_model.h" +#include "model.h" #include #include #include diff --git a/source/source_md/module_snap/snap_model.h b/source/source_md/module_snap/model.h similarity index 100% rename from source/source_md/module_snap/snap_model.h rename to source/source_md/module_snap/model.h diff --git a/source/source_md/module_snap/unittests/CMakeLists.txt b/source/source_md/module_snap/unittests/CMakeLists.txt index b4358603474..c323e0393f6 100644 --- a/source/source_md/module_snap/unittests/CMakeLists.txt +++ b/source/source_md/module_snap/unittests/CMakeLists.txt @@ -1,21 +1,21 @@ AddTest( TARGET MODULE_MD_SNAP_model - SOURCES test_snap_model.cpp ../snap_model.cpp + SOURCES test_model.cpp ../model.cpp ) AddTest( TARGET MODULE_MD_SNAP_clebsch_gordan - SOURCES test_snap_clebsch_gordan.cpp ../snap_clebsch_gordan.cpp + SOURCES test_cg.cpp ../cg.cpp ) AddTest( TARGET MODULE_MD_SNAP_descriptor LIBS base device - SOURCES test_snap_descriptor.cpp ../snap_descriptor.cpp ../snap_descriptor_derivative.cpp ../snap_model.cpp ../snap_clebsch_gordan.cpp + SOURCES test_desc.cpp ../desc.cpp ../deriv.cpp ../model.cpp ../cg.cpp ) AddTest( TARGET MODULE_MD_SNAP_calculator LIBS base device - SOURCES test_snap_calculator.cpp ../snap_calculator.cpp ../snap_descriptor.cpp ../snap_descriptor_derivative.cpp ../snap_model.cpp ../snap_clebsch_gordan.cpp + SOURCES test_calc.cpp ../calc.cpp ../desc.cpp ../deriv.cpp ../model.cpp ../cg.cpp ) diff --git a/source/source_md/module_snap/unittests/test_snap_calculator.cpp b/source/source_md/module_snap/unittests/test_calc.cpp similarity index 99% rename from source/source_md/module_snap/unittests/test_snap_calculator.cpp rename to source/source_md/module_snap/unittests/test_calc.cpp index 33ef835cd02..24d1fe049f8 100644 --- a/source/source_md/module_snap/unittests/test_snap_calculator.cpp +++ b/source/source_md/module_snap/unittests/test_calc.cpp @@ -1,4 +1,4 @@ -#include "../snap_calculator.h" +#include "../calc.h" #include diff --git a/source/source_md/module_snap/unittests/test_snap_clebsch_gordan.cpp b/source/source_md/module_snap/unittests/test_cg.cpp similarity index 96% rename from source/source_md/module_snap/unittests/test_snap_clebsch_gordan.cpp rename to source/source_md/module_snap/unittests/test_cg.cpp index 0639ccabfa3..436d4a743f9 100644 --- a/source/source_md/module_snap/unittests/test_snap_clebsch_gordan.cpp +++ b/source/source_md/module_snap/unittests/test_cg.cpp @@ -1,4 +1,4 @@ -#include "../snap_clebsch_gordan.h" +#include "../cg.h" #include diff --git a/source/source_md/module_snap/unittests/test_snap_descriptor.cpp b/source/source_md/module_snap/unittests/test_desc.cpp similarity index 99% rename from source/source_md/module_snap/unittests/test_snap_descriptor.cpp rename to source/source_md/module_snap/unittests/test_desc.cpp index 0514dd4f6ae..eedd5f56dd8 100644 --- a/source/source_md/module_snap/unittests/test_snap_descriptor.cpp +++ b/source/source_md/module_snap/unittests/test_desc.cpp @@ -1,4 +1,4 @@ -#include "../snap_descriptor.h" +#include "../desc.h" #include diff --git a/source/source_md/module_snap/unittests/test_snap_model.cpp b/source/source_md/module_snap/unittests/test_model.cpp similarity index 99% rename from source/source_md/module_snap/unittests/test_snap_model.cpp rename to source/source_md/module_snap/unittests/test_model.cpp index 691c56b550e..a697978dda4 100644 --- a/source/source_md/module_snap/unittests/test_snap_model.cpp +++ b/source/source_md/module_snap/unittests/test_model.cpp @@ -1,4 +1,4 @@ -#include "../snap_model.h" +#include "../model.h" #include From 892a38423a26568279f2a6594b254b530cae7a9e Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 13:24:59 +0800 Subject: [PATCH 20/33] refactor: shorten SNAP identifiers to 15 characters --- source/source_esolver/snap_solver.cpp | 24 ++--- source/source_esolver/snap_solver.h | 4 +- source/source_md/module_snap/calc.cpp | 50 +++++----- source/source_md/module_snap/calc.h | 18 ++-- source/source_md/module_snap/cg.cpp | 16 ++-- source/source_md/module_snap/cg.h | 12 +-- source/source_md/module_snap/deriv.cpp | 2 +- source/source_md/module_snap/desc.cpp | 38 ++++---- source/source_md/module_snap/desc.h | 22 ++--- source/source_md/module_snap/model.cpp | 66 ++++++------- source/source_md/module_snap/model.h | 8 +- .../module_snap/unittests/test_calc.cpp | 96 +++++++++---------- .../module_snap/unittests/test_cg.cpp | 12 +-- .../module_snap/unittests/test_desc.cpp | 24 ++--- .../module_snap/unittests/test_model.cpp | 72 +++++++------- 15 files changed, 232 insertions(+), 232 deletions(-) diff --git a/source/source_esolver/snap_solver.cpp b/source/source_esolver/snap_solver.cpp index 8fe03475504..0311c01307c 100644 --- a/source/source_esolver/snap_solver.cpp +++ b/source/source_esolver/snap_solver.cpp @@ -50,7 +50,7 @@ ModuleMD::SNAP::Neighbor make_neighbor(const NeighborAtom& center, + parameters.element_radii[static_cast(neighbor.atom_type)]) * parameters.rcutfac; result.element_index = static_cast(neighbor.atom_type); - if (parameters.switchinner_flag) + if (parameters.inner_flag) { const std::size_t center_type = static_cast(center.atom_type); const std::size_t neighbor_type = static_cast(neighbor.atom_type); @@ -61,10 +61,10 @@ ModuleMD::SNAP::Neighbor make_neighbor(const NeighborAtom& center, } } -ESolver_SNAP::ESolver_SNAP(const std::string& coefficient_file, +ESolver_SNAP::ESolver_SNAP(const std::string& coeff_file, const std::string& parameter_file, std::ofstream& running_log) - : coefficient_file_(coefficient_file), parameter_file_(parameter_file), running_log_(running_log) + : coeff_file_(coeff_file), parameter_file_(parameter_file), running_log_(running_log) { classname = "ESolver_SNAP"; } @@ -72,17 +72,17 @@ ESolver_SNAP::ESolver_SNAP(const std::string& coefficient_file, void ESolver_SNAP::initialize(const std::vector& labels) { std::string error; - if (!model_.load(coefficient_file_, parameter_file_, labels, error)) + if (!model_.load(coeff_file_, parameter_file_, labels, error)) { fail(error); } - const std::string coefficient_path = full_path(coefficient_file_); + const std::string coeff_path = full_path(coeff_file_); const std::string parameter_path = full_path(parameter_file_); - running_log_ << " Read SNAP coefficient file: " << coefficient_path << std::endl; + running_log_ << " Read SNAP coefficient file: " << coeff_path << std::endl; running_log_ << " Read SNAP parameter file: " << parameter_path << std::endl; if (GlobalV::MY_RANK == 0) { - std::cout << " Read SNAP coefficient file: " << coefficient_path << std::endl; + std::cout << " Read SNAP coefficient file: " << coeff_path << std::endl; std::cout << " Read SNAP parameter file: " << parameter_path << std::endl; } calculator_.reset(new ModuleMD::SNAP::Calculator(model_)); @@ -141,7 +141,7 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) i, i); std::vector neighbors; - std::vector neighbor_indices; + std::vector neigh_indices; for (int k = 0; k < list.get_numneigh(i); ++k) { const int neighbor_index = list.get_firstneigh(i)[k]; @@ -151,12 +151,12 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) fail("MDCell atom type is outside the SNAP element map."); } neighbors.push_back(make_neighbor(center, neighbor, mdcell.lat0(), model_.parameters)); - neighbor_indices.push_back(static_cast(neighbor_index)); + neigh_indices.push_back(static_cast(neighbor_index)); } const std::size_t center_element = static_cast(center.atom_type); - const ModuleMD::SNAP::ForceResult result = calculator_->compute_with_analytic_force(neighbors, center_element); + const ModuleMD::SNAP::ForceResult result = calculator_->eval_force(neighbors, center_element); const std::size_t center_index = static_cast(i); - contribution.add(center_index, neighbor_indices, neighbors, result); + contribution.add(center_index, neigh_indices, neighbors, result); } snap_potential_ = contribution.energy() / ModuleBase::Ry_to_eV; const double virial_scale = 1.0 / (ModuleBase::Ry_to_eV * mdcell.omega()); @@ -218,7 +218,7 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) atom_indices.push_back(index); } const std::size_t center_element = static_cast(center.atom_type); - const ModuleMD::SNAP::ForceResult result = calculator_->compute_with_analytic_force(neighbors, center_element); + const ModuleMD::SNAP::ForceResult result = calculator_->eval_force(neighbors, center_element); const int center_index = offsets[static_cast(center.atom_type)] + center.atom_index; const std::size_t index = static_cast(center_index); contribution.add(index, atom_indices, neighbors, result); diff --git a/source/source_esolver/snap_solver.h b/source/source_esolver/snap_solver.h index fd95047305a..850fc22b62e 100644 --- a/source/source_esolver/snap_solver.h +++ b/source/source_esolver/snap_solver.h @@ -15,7 +15,7 @@ namespace ModuleESolver class ESolver_SNAP : public ESolver { public: - ESolver_SNAP(const std::string& coefficient_file, + ESolver_SNAP(const std::string& coeff_file, const std::string& parameter_file, std::ofstream& running_log); @@ -29,7 +29,7 @@ class ESolver_SNAP : public ESolver private: void initialize(const std::vector& labels); - std::string coefficient_file_; + std::string coeff_file_; std::string parameter_file_; std::ofstream& running_log_; ModuleMD::SNAP::ModelData model_; diff --git a/source/source_md/module_snap/calc.cpp b/source/source_md/module_snap/calc.cpp index 4fedbd3a66a..1e998527c04 100644 --- a/source/source_md/module_snap/calc.cpp +++ b/source/source_md/module_snap/calc.cpp @@ -9,18 +9,18 @@ namespace SNAP Calculator::Calculator(const ModelData& model) : model_(model), - descriptor_evaluator_(model.parameters), - descriptor_size_(0) + desc_eval_(model.parameters), + desc_size_(0) { - const std::size_t channels = descriptor_evaluator_.channel_count(); - descriptor_size_ = descriptor_evaluator_.bispectrum_size() * channels * channels * channels; + const std::size_t channels = desc_eval_.channel_count(); + desc_size_ = desc_eval_.bispectrum_size() * channels * channels * channels; if (model_.coefficients.size() != model_.parameters.elements.size()) { throw std::invalid_argument("SNAP coefficient blocks do not match the element list."); } - const std::size_t expected_count = descriptor_size_ + 1 + const std::size_t expected_count = desc_size_ + 1 + (model_.parameters.quadratic_flag - ? descriptor_size_ * (descriptor_size_ + 1) / 2 + ? desc_size_ * (desc_size_ + 1) / 2 : 0); for (std::size_t element = 0; element < model_.coefficients.size(); ++element) { @@ -39,13 +39,13 @@ EnergyResult Calculator::compute(const std::vector& neighbors, const s } EnergyResult result; - result.descriptor = descriptor_evaluator_.compute_bispectrum( - descriptor_evaluator_.accumulate_u(neighbors, central_element)); + result.descriptor = desc_eval_.calc_bispec( + desc_eval_.accumulate_u(neighbors, central_element)); if (model_.parameters.bzero_flag) { const std::vector bzero = - descriptor_evaluator_.compute_bispectrum( - descriptor_evaluator_.accumulate_u(std::vector(), central_element)); + desc_eval_.calc_bispec( + desc_eval_.accumulate_u(std::vector(), central_element)); for (std::size_t index = 0; index < result.descriptor.size(); ++index) { result.descriptor[index] -= bzero[index]; @@ -72,7 +72,7 @@ EnergyResult Calculator::compute(const std::vector& neighbors, const s return result; } -ForceResult Calculator::compute_with_analytic_force(const std::vector& neighbors, +ForceResult Calculator::eval_force(const std::vector& neighbors, const std::size_t central_element) const { if (central_element >= model_.coefficients.size()) @@ -84,24 +84,24 @@ ForceResult Calculator::compute_with_analytic_force(const std::vector& result.center_force.assign(3, 0.0); result.neighbor_forces.assign(neighbors.size(), std::vector(3, 0.0)); const std::vector& coefficients = model_.coefficients[central_element]; - const std::vector > u = descriptor_evaluator_.accumulate_u(neighbors, central_element); + const std::vector > u = desc_eval_.accumulate_u(neighbors, central_element); for (std::size_t neighbor_index = 0; neighbor_index < neighbors.size(); ++neighbor_index) { for (int direction = 0; direction < 3; ++direction) { const UWithDerivative u_derivative = - descriptor_evaluator_.compute_u_with_derivative(neighbors[neighbor_index], direction); + desc_eval_.calc_u_deriv(neighbors[neighbor_index], direction); std::vector > du(u.size(), std::complex(0.0, 0.0)); - const std::size_t derivative_offset = model_.parameters.chem_flag + const std::size_t deriv_offset = model_.parameters.chem_flag ? neighbors[neighbor_index].element_index - * descriptor_evaluator_.u_size() + * desc_eval_.u_size() : 0; - const std::vector >& one_neighbor_derivative = u_derivative.derivatives; - for (std::size_t index = 0; index < one_neighbor_derivative.size(); ++index) + const std::vector >& one_neigh_deriv = u_derivative.derivatives; + for (std::size_t index = 0; index < one_neigh_deriv.size(); ++index) { - du[derivative_offset + index] = one_neighbor_derivative[index]; + du[deriv_offset + index] = one_neigh_deriv[index]; } - const std::vector db = descriptor_evaluator_.compute_bispectrum_derivative(u, du); + const std::vector db = desc_eval_.calc_b_deriv(u, du); double derivative = 0.0; for (std::size_t index = 0; index < db.size(); ++index) { @@ -128,7 +128,7 @@ ForceResult Calculator::compute_with_analytic_force(const std::vector& return result; } -ForceResult Calculator::compute_with_finite_difference_force(const std::vector& neighbors, +ForceResult Calculator::eval_force_fd(const std::vector& neighbors, const std::size_t central_element, const double displacement) const { @@ -181,18 +181,18 @@ CellAccumulator::CellAccumulator(const std::size_t atom_count) : forces_(atom_co } void CellAccumulator::add(const std::size_t center_index, - const std::vector& neighbor_indices, + const std::vector& neigh_indices, const std::vector& neighbors, const ForceResult& result) { - if (center_index >= forces_.size() || neighbor_indices.size() != neighbors.size() + if (center_index >= forces_.size() || neigh_indices.size() != neighbors.size() || result.neighbor_forces.size() != neighbors.size() || result.center_force.size() != 3) { throw std::invalid_argument("SNAP cell contribution has inconsistent atom or force indices."); } - for (std::size_t index = 0; index < neighbor_indices.size(); ++index) + for (std::size_t index = 0; index < neigh_indices.size(); ++index) { - if (neighbor_indices[index] >= forces_.size() || result.neighbor_forces[index].size() != 3) + if (neigh_indices[index] >= forces_.size() || result.neighbor_forces[index].size() != 3) { throw std::invalid_argument("SNAP neighbor force index is outside the cell."); } @@ -208,7 +208,7 @@ void CellAccumulator::add(const std::size_t center_index, { const Neighbor& neighbor = neighbors[index]; const double displacement[3] = {neighbor.x, neighbor.y, neighbor.z}; - const std::size_t atom = neighbor_indices[index]; + const std::size_t atom = neigh_indices[index]; for (int direction = 0; direction < 3; ++direction) { forces_[atom][static_cast(direction)] += diff --git a/source/source_md/module_snap/calc.h b/source/source_md/module_snap/calc.h index 92b2a745910..6e1791f3cbb 100644 --- a/source/source_md/module_snap/calc.h +++ b/source/source_md/module_snap/calc.h @@ -1,5 +1,5 @@ -#ifndef SNAP_CALCULATOR_H -#define SNAP_CALCULATOR_H +#ifndef SNAP_CALC_H +#define SNAP_CALC_H #include "desc.h" #include "model.h" @@ -32,22 +32,22 @@ class Calculator EnergyResult compute(const std::vector& neighbors, std::size_t central_element) const; - ForceResult compute_with_analytic_force(const std::vector& neighbors, + ForceResult eval_force(const std::vector& neighbors, std::size_t central_element) const; - ForceResult compute_with_finite_difference_force(const std::vector& neighbors, + ForceResult eval_force_fd(const std::vector& neighbors, std::size_t central_element, double displacement) const; std::size_t descriptor_size() const { - return descriptor_size_; + return desc_size_; } private: ModelData model_; - DescriptorEvaluator descriptor_evaluator_; - std::size_t descriptor_size_; + DescEval desc_eval_; + std::size_t desc_size_; }; class CellAccumulator @@ -56,7 +56,7 @@ class CellAccumulator explicit CellAccumulator(std::size_t atom_count); void add(std::size_t center_index, - const std::vector& neighbor_indices, + const std::vector& neigh_indices, const std::vector& neighbors, const ForceResult& result); @@ -73,4 +73,4 @@ class CellAccumulator } // namespace SNAP } // namespace ModuleMD -#endif // SNAP_CALCULATOR_H +#endif // SNAP_CALC_H diff --git a/source/source_md/module_snap/cg.cpp b/source/source_md/module_snap/cg.cpp index 79404bff331..bfa3e5eb372 100644 --- a/source/source_md/module_snap/cg.cpp +++ b/source/source_md/module_snap/cg.cpp @@ -15,7 +15,7 @@ int half_sum(const int left, const int right) } } -ClebschGordanTable::ClebschGordanTable(const int twojmax) +CGTable::CGTable(const int twojmax) { twojmax_ = twojmax < 0 ? 0 : twojmax; for (int j1 = 0; j1 <= twojmax_; ++j1) @@ -40,7 +40,7 @@ ClebschGordanTable::ClebschGordanTable(const int twojmax) entry.m2 = m2; entry.j = j; entry.m = m; - entry.value = coefficient_uncached(j1, m1, j2, m2, j, m); + entry.value = coeff_raw(j1, m1, j2, m2, j, m); entries_.push_back(entry); } } @@ -49,7 +49,7 @@ ClebschGordanTable::ClebschGordanTable(const int twojmax) } } -double ClebschGordanTable::factorial(const int value) +double CGTable::factorial(const int value) { if (value < 0) { @@ -58,7 +58,7 @@ double ClebschGordanTable::factorial(const int value) return std::tgamma(static_cast(value) + 1.0); } -bool ClebschGordanTable::allowed(const int j1, +bool CGTable::allowed(const int j1, const int m1, const int j2, const int m2, @@ -80,7 +80,7 @@ bool ClebschGordanTable::allowed(const int j1, return m == m1 + m2; } -double ClebschGordanTable::coefficient_uncached(const int j1, +double CGTable::coeff_raw(const int j1, const int m1, const int j2, const int m2, @@ -123,7 +123,7 @@ double ClebschGordanTable::coefficient_uncached(const int j1, return delta * prefactor * sum; } -const ClebschGordanTable::Entry* ClebschGordanTable::find(const int j1, +const CGTable::Entry* CGTable::find(const int j1, const int m1, const int j2, const int m2, @@ -141,7 +141,7 @@ const ClebschGordanTable::Entry* ClebschGordanTable::find(const int j1, return nullptr; } -double ClebschGordanTable::coefficient(const int j1, +double CGTable::coefficient(const int j1, const int m1, const int j2, const int m2, @@ -152,7 +152,7 @@ double ClebschGordanTable::coefficient(const int j1, return entry == nullptr ? 0.0 : entry->value; } -double ClebschGordanTable::h_coefficient(const int j1, +double CGTable::h_coefficient(const int j1, const int m1, const int mp1, const int j2, diff --git a/source/source_md/module_snap/cg.h b/source/source_md/module_snap/cg.h index 978c255d985..01cc732e18f 100644 --- a/source/source_md/module_snap/cg.h +++ b/source/source_md/module_snap/cg.h @@ -1,5 +1,5 @@ -#ifndef SNAP_CLEBSCH_GORDAN_H -#define SNAP_CLEBSCH_GORDAN_H +#ifndef SNAP_CG_H +#define SNAP_CG_H #include @@ -14,10 +14,10 @@ namespace SNAP * If the stored index is j, the physical angular momentum is j/2. The same * convention is used for m and m'. */ -class ClebschGordanTable +class CGTable { public: - explicit ClebschGordanTable(int twojmax); + explicit CGTable(int twojmax); double coefficient(int j1, int m1, int j2, int m2, int j, int m) const; @@ -44,7 +44,7 @@ class ClebschGordanTable }; static bool allowed(int j1, int m1, int j2, int m2, int j, int m); - static double coefficient_uncached(int j1, int m1, int j2, int m2, int j, int m); + static double coeff_raw(int j1, int m1, int j2, int m2, int j, int m); static double factorial(int value); const Entry* find(int j1, int m1, int j2, int m2, int j, int m) const; @@ -55,4 +55,4 @@ class ClebschGordanTable } // namespace SNAP } // namespace ModuleMD -#endif // SNAP_CLEBSCH_GORDAN_H +#endif // SNAP_CG_H diff --git a/source/source_md/module_snap/deriv.cpp b/source/source_md/module_snap/deriv.cpp index e59f35a5eb3..61fd87a0b50 100644 --- a/source/source_md/module_snap/deriv.cpp +++ b/source/source_md/module_snap/deriv.cpp @@ -106,7 +106,7 @@ Dual dual_tan(const Dual& value) } } -UWithDerivative DescriptorEvaluator::compute_u_with_derivative(const Neighbor& neighbor, const int direction) const +UWithDerivative DescEval::calc_u_deriv(const Neighbor& neighbor, const int direction) const { if (direction < 0 || direction > 2) { diff --git a/source/source_md/module_snap/desc.cpp b/source/source_md/module_snap/desc.cpp index 42e65f294a2..43f02919001 100644 --- a/source/source_md/module_snap/desc.cpp +++ b/source/source_md/module_snap/desc.cpp @@ -11,7 +11,7 @@ namespace ModuleMD namespace SNAP { -DescriptorEvaluator::DescriptorEvaluator(const ModelParameters& parameters) +DescEval::DescEval(const ModelParameters& parameters) : parameters_(parameters), cg_table_(parameters.twojmax), u_size_(0) { std::string error; @@ -40,14 +40,14 @@ DescriptorEvaluator::DescriptorEvaluator(const ModelParameters& parameters) index.j1 = j1; index.j2 = j2; index.j = j; - bispectrum_indices_.push_back(index); + bispec_indices_.push_back(index); } } } } } -void DescriptorEvaluator::compute_rootpq() +void DescEval::compute_rootpq() { const int dimension = parameters_.twojmax + 1; rootpq_.assign(static_cast(dimension * dimension), 0.0); @@ -60,12 +60,12 @@ void DescriptorEvaluator::compute_rootpq() } } -std::size_t DescriptorEvaluator::u_index(const int j, const int ma, const int mb) const +std::size_t DescEval::u_index(const int j, const int ma, const int mb) const { return u_block_[static_cast(j)] + static_cast(mb * (j + 1) + ma); } -DescriptorEvaluator::SwitchValue DescriptorEvaluator::switching(const double distance, +DescEval::SwitchValue DescEval::switching(const double distance, const Neighbor& neighbor, const double cutoff_radius) const { @@ -84,7 +84,7 @@ DescriptorEvaluator::SwitchValue DescriptorEvaluator::switching(const double dis result.value = 0.5 * (std::cos(angle) + 1.0); result.derivative = -0.5 * std::sin(angle) * angle_scale; } - if (parameters_.switchinner_flag) + if (parameters_.inner_flag) { const double inner_start = neighbor.sinner - neighbor.dinner; const double inner_end = neighbor.sinner + neighbor.dinner; @@ -98,15 +98,15 @@ DescriptorEvaluator::SwitchValue DescriptorEvaluator::switching(const double dis const double angle_scale = 0.5 * ModuleBase::PI / neighbor.dinner; const double angle = (distance - inner_start) * angle_scale; const double inner_value = 0.5 * (1.0 - std::cos(angle)); - const double inner_derivative = 0.5 * std::sin(angle) * angle_scale; - result.derivative = result.derivative * inner_value + result.value * inner_derivative; + const double inner_deriv = 0.5 * std::sin(angle) * angle_scale; + result.derivative = result.derivative * inner_value + result.value * inner_deriv; result.value *= inner_value; } } return result; } -std::vector > DescriptorEvaluator::compute_u(const Neighbor& neighbor) const +std::vector > DescEval::compute_u(const Neighbor& neighbor) const { const double rsq = neighbor.x * neighbor.x + neighbor.y * neighbor.y + neighbor.z * neighbor.z; const double distance = std::sqrt(rsq); @@ -162,12 +162,12 @@ std::vector > DescriptorEvaluator::compute_u(const Neighbor return result; } -std::vector > DescriptorEvaluator::accumulate_u(const std::vector& neighbors) const +std::vector > DescEval::accumulate_u(const std::vector& neighbors) const { return accumulate_u(neighbors, 0); } -std::vector > DescriptorEvaluator::accumulate_u(const std::vector& neighbors, +std::vector > DescEval::accumulate_u(const std::vector& neighbors, const std::size_t central_element) const { const std::size_t channels = channel_count(); @@ -217,20 +217,20 @@ std::vector > DescriptorEvaluator::accumulate_u(const std:: return result; } -std::vector DescriptorEvaluator::compute_bispectrum(const std::vector >& u) const +std::vector DescEval::calc_bispec(const std::vector >& u) const { const std::size_t channels = channel_count(); if (u.size() != channels * u_size_) { throw std::invalid_argument("SNAP u array has an unexpected size."); } - const std::size_t bispectrum_size = bispectrum_indices_.size(); + const std::size_t bispectrum_size = bispec_indices_.size(); std::vector result(channels * channels * channels * bispectrum_size, 0.0); const auto compute_one = [this, &u](const std::size_t first_channel, const std::size_t second_channel, const std::size_t third_channel, - const std::size_t bispectrum_index) { - const BispectrumIndex& index = bispectrum_indices_[bispectrum_index]; + const std::size_t bispec_index) { + const BispectrumIndex& index = bispec_indices_[bispec_index]; const std::size_t first_offset = first_channel * u_size_; const std::size_t second_offset = second_channel * u_size_; const std::size_t third_offset = third_channel * u_size_; @@ -305,7 +305,7 @@ std::vector DescriptorEvaluator::compute_bispectrum(const std::vector DescriptorEvaluator::compute_bispectrum_derivative( +std::vector DescEval::calc_b_deriv( const std::vector >& u, const std::vector >& du) const { @@ -314,13 +314,13 @@ std::vector DescriptorEvaluator::compute_bispectrum_derivative( { throw std::invalid_argument("SNAP u derivative array has an unexpected size."); } - const std::size_t bispectrum_size = bispectrum_indices_.size(); + const std::size_t bispectrum_size = bispec_indices_.size(); std::vector result(channels * channels * channels * bispectrum_size, 0.0); const auto compute_one = [this, &u, &du](const std::size_t first_channel, const std::size_t second_channel, const std::size_t third_channel, - const std::size_t bispectrum_index) { - const BispectrumIndex& index = bispectrum_indices_[bispectrum_index]; + const std::size_t bispec_index) { + const BispectrumIndex& index = bispec_indices_[bispec_index]; const std::size_t first_offset = first_channel * u_size_; const std::size_t second_offset = second_channel * u_size_; const std::size_t third_offset = third_channel * u_size_; diff --git a/source/source_md/module_snap/desc.h b/source/source_md/module_snap/desc.h index 367ca1115ac..ec2a601e3aa 100644 --- a/source/source_md/module_snap/desc.h +++ b/source/source_md/module_snap/desc.h @@ -1,5 +1,5 @@ -#ifndef SNAP_DESCRIPTOR_H -#define SNAP_DESCRIPTOR_H +#ifndef SNAP_DESC_H +#define SNAP_DESC_H #include "cg.h" #include "model.h" @@ -30,23 +30,23 @@ struct UWithDerivative std::vector > derivatives; }; -class DescriptorEvaluator +class DescEval { public: - explicit DescriptorEvaluator(const ModelParameters& parameters); + explicit DescEval(const ModelParameters& parameters); std::vector > compute_u(const Neighbor& neighbor) const; - UWithDerivative compute_u_with_derivative(const Neighbor& neighbor, int direction) const; + UWithDerivative calc_u_deriv(const Neighbor& neighbor, int direction) const; std::vector > accumulate_u(const std::vector& neighbors) const; std::vector > accumulate_u(const std::vector& neighbors, std::size_t central_element) const; - std::vector compute_bispectrum(const std::vector >& u) const; + std::vector calc_bispec(const std::vector >& u) const; - std::vector compute_bispectrum_derivative(const std::vector >& u, + std::vector calc_b_deriv(const std::vector >& u, const std::vector >& du) const; std::size_t u_size() const @@ -56,7 +56,7 @@ class DescriptorEvaluator std::size_t bispectrum_size() const { - return bispectrum_indices_.size(); + return bispec_indices_.size(); } std::size_t channel_count() const @@ -82,14 +82,14 @@ class DescriptorEvaluator void compute_rootpq(); ModelParameters parameters_; - ClebschGordanTable cg_table_; + CGTable cg_table_; std::vector rootpq_; std::vector u_block_; - std::vector bispectrum_indices_; + std::vector bispec_indices_; std::size_t u_size_; }; } // namespace SNAP } // namespace ModuleMD -#endif // SNAP_DESCRIPTOR_H +#endif // SNAP_DESC_H diff --git a/source/source_md/module_snap/model.cpp b/source/source_md/module_snap/model.cpp index bf7cfb41ae9..04d9c3d9382 100644 --- a/source/source_md/module_snap/model.cpp +++ b/source/source_md/module_snap/model.cpp @@ -26,7 +26,7 @@ bool next_data_line(std::istream& input, std::string& line) } template -bool read_parameter_value(std::istringstream& words, T& value, const std::string& keyword, std::string& error) +bool read_param(std::istringstream& words, T& value, const std::string& keyword, std::string& error) { if (!(words >> value) || words.fail()) { @@ -38,7 +38,7 @@ bool read_parameter_value(std::istringstream& words, T& value, const std::string bool validate_inner(const ModuleMD::SNAP::ModelParameters& parameters, std::string& error) { - if (!parameters.switchinner_flag) + if (!parameters.inner_flag) { return true; } @@ -75,7 +75,7 @@ bool validate_cutoff(const ModuleMD::SNAP::ModelParameters& parameters, std::str return true; } -bool validate_pair_cutoffs(const ModuleMD::SNAP::ModelParameters& parameters, std::string& error) +bool valid_cutoffs(const ModuleMD::SNAP::ModelParameters& parameters, std::string& error) { for (std::size_t i = 0; i < parameters.element_radii.size(); ++i) { @@ -148,33 +148,33 @@ bool ModelParameters::valid(std::string& error) const return false; } } - if (!validate_pair_cutoffs(*this, error)) + if (!valid_cutoffs(*this, error)) { return false; } return true; } -bool ModelData::load(const std::string& coefficient_file, +bool ModelData::load(const std::string& coeff_file, const std::string& parameter_file, - const std::vector& requested_elements, + const std::vector& wanted_elements, std::string& error) { error.clear(); parameters = ModelParameters(); parameters.rfac0 = 0.99363; coefficients.clear(); - parameters.elements = requested_elements; + parameters.elements = wanted_elements; if (parameters.elements.empty()) { error = "SNAP requires at least one requested element."; return false; } - std::ifstream coeff_stream(coefficient_file.c_str()); + std::ifstream coeff_stream(coeff_file.c_str()); if (!coeff_stream) { - error = "Cannot open SNAP coefficient file: " + coefficient_file; + error = "Cannot open SNAP coefficient file: " + coeff_file; return false; } @@ -186,8 +186,8 @@ bool ModelData::load(const std::string& coefficient_file, } std::istringstream header(line); int block_count = 0; - int coefficient_count = 0; - if (!(header >> block_count >> coefficient_count) || block_count <= 0 || coefficient_count <= 0) + int coeff_count = 0; + if (!(header >> block_count >> coeff_count) || block_count <= 0 || coeff_count <= 0) { error = "Invalid SNAP coefficient file header."; return false; @@ -222,8 +222,8 @@ bool ModelData::load(const std::string& coefficient_file, break; } } - std::vector values(static_cast(coefficient_count), 0.0); - for (int coefficient = 0; coefficient < coefficient_count; ++coefficient) + std::vector values(static_cast(coeff_count), 0.0); + for (int coefficient = 0; coefficient < coeff_count; ++coefficient) { if (!next_data_line(coeff_stream, line)) { @@ -259,8 +259,8 @@ bool ModelData::load(const std::string& coefficient_file, } } - std::ifstream parameter_stream(parameter_file.c_str()); - if (!parameter_stream) + std::ifstream param_stream(parameter_file.c_str()); + if (!param_stream) { error = "Cannot open SNAP parameter file: " + parameter_file; return false; @@ -269,14 +269,14 @@ bool ModelData::load(const std::string& coefficient_file, bool has_twojmax = false; bool has_sinner = false; bool has_dinner = false; - while (next_data_line(parameter_stream, line)) + while (next_data_line(param_stream, line)) { std::istringstream words(line); std::string keyword; words >> keyword; if (keyword == "rcutfac") { - if (!read_parameter_value(words, parameters.rcutfac, keyword, error)) + if (!read_param(words, parameters.rcutfac, keyword, error)) { return false; } @@ -284,7 +284,7 @@ bool ModelData::load(const std::string& coefficient_file, } else if (keyword == "twojmax") { - if (!read_parameter_value(words, parameters.twojmax, keyword, error)) + if (!read_param(words, parameters.twojmax, keyword, error)) { return false; } @@ -292,14 +292,14 @@ bool ModelData::load(const std::string& coefficient_file, } else if (keyword == "rfac0") { - if (!read_parameter_value(words, parameters.rfac0, keyword, error)) + if (!read_param(words, parameters.rfac0, keyword, error)) { return false; } } else if (keyword == "rmin0") { - if (!read_parameter_value(words, parameters.rmin, keyword, error)) + if (!read_param(words, parameters.rmin, keyword, error)) { return false; } @@ -307,7 +307,7 @@ bool ModelData::load(const std::string& coefficient_file, else if (keyword == "bnormflag") { int value = 0; - if (!read_parameter_value(words, value, keyword, error)) + if (!read_param(words, value, keyword, error)) { return false; } @@ -316,7 +316,7 @@ bool ModelData::load(const std::string& coefficient_file, else if (keyword == "switchflag") { int value = 0; - if (!read_parameter_value(words, value, keyword, error)) + if (!read_param(words, value, keyword, error)) { return false; } @@ -325,7 +325,7 @@ bool ModelData::load(const std::string& coefficient_file, else if (keyword == "bzeroflag") { int value = 0; - if (!read_parameter_value(words, value, keyword, error)) + if (!read_param(words, value, keyword, error)) { return false; } @@ -334,7 +334,7 @@ bool ModelData::load(const std::string& coefficient_file, else if (keyword == "quadraticflag") { int value = 0; - if (!read_parameter_value(words, value, keyword, error)) + if (!read_param(words, value, keyword, error)) { return false; } @@ -343,7 +343,7 @@ bool ModelData::load(const std::string& coefficient_file, else if (keyword == "wselfallflag") { int value = 0; - if (!read_parameter_value(words, value, keyword, error)) + if (!read_param(words, value, keyword, error)) { return false; } @@ -352,7 +352,7 @@ bool ModelData::load(const std::string& coefficient_file, else if (keyword == "chemflag") { int value = 0; - if (!read_parameter_value(words, value, keyword, error)) + if (!read_param(words, value, keyword, error)) { return false; } @@ -361,7 +361,7 @@ bool ModelData::load(const std::string& coefficient_file, else if (keyword == "switchinnerflag") { int value = 0; - if (!read_parameter_value(words, value, keyword, error)) + if (!read_param(words, value, keyword, error)) { return false; } @@ -370,7 +370,7 @@ bool ModelData::load(const std::string& coefficient_file, error = "SNAP switchinnerflag must be 0 or 1."; return false; } - parameters.switchinner_flag = value == 1; + parameters.inner_flag = value == 1; } else if (keyword == "sinner" || keyword == "dinner") { @@ -378,7 +378,7 @@ bool ModelData::load(const std::string& coefficient_file, values.resize(parameters.elements.size()); for (std::size_t i = 0; i < values.size(); ++i) { - if (!read_parameter_value(words, values[i], keyword, error)) + if (!read_param(words, values[i], keyword, error)) { return false; } @@ -395,7 +395,7 @@ bool ModelData::load(const std::string& coefficient_file, else if (keyword == "chunksize" || keyword == "parallelthresh") { int value = 0; - if (!read_parameter_value(words, value, keyword, error)) + if (!read_param(words, value, keyword, error)) { return false; } @@ -417,12 +417,12 @@ bool ModelData::load(const std::string& coefficient_file, return false; } } - if (parameters.switchinner_flag && (!has_sinner || !has_dinner)) + if (parameters.inner_flag && (!has_sinner || !has_dinner)) { error = "SNAP switchinnerflag=1 requires sinner and dinner."; return false; } - if (!parameters.switchinner_flag && (has_sinner || has_dinner)) + if (!parameters.inner_flag && (has_sinner || has_dinner)) { error = "SNAP sinner and dinner require switchinnerflag=1."; return false; @@ -441,7 +441,7 @@ bool ModelData::load(const std::string& coefficient_file, return parameters.valid(error); } -std::size_t ModelData::coefficient_count() const +std::size_t ModelData::coeff_count() const { if (coefficients.empty()) { diff --git a/source/source_md/module_snap/model.h b/source/source_md/module_snap/model.h index 806018c19b3..e00b642ff50 100644 --- a/source/source_md/module_snap/model.h +++ b/source/source_md/module_snap/model.h @@ -22,7 +22,7 @@ struct ModelParameters bool bzero_flag = true; bool quadratic_flag = false; bool wselfall_flag = false; - bool switchinner_flag = false; + bool inner_flag = false; double wself = 1.0; std::vector elements; std::vector element_weights; @@ -38,12 +38,12 @@ struct ModelData ModelParameters parameters; std::vector > coefficients; - bool load(const std::string& coefficient_file, + bool load(const std::string& coeff_file, const std::string& parameter_file, - const std::vector& requested_elements, + const std::vector& wanted_elements, std::string& error); - std::size_t coefficient_count() const; + std::size_t coeff_count() const; }; } // namespace SNAP diff --git a/source/source_md/module_snap/unittests/test_calc.cpp b/source/source_md/module_snap/unittests/test_calc.cpp index 24d1fe049f8..a4e5f225c05 100644 --- a/source/source_md/module_snap/unittests/test_calc.cpp +++ b/source/source_md/module_snap/unittests/test_calc.cpp @@ -23,7 +23,7 @@ ModuleMD::SNAP::ModelData make_model() return model; } -ModuleMD::SNAP::ModelData make_multi_element_model() +ModuleMD::SNAP::ModelData multi_model() { ModuleMD::SNAP::ModelData model; model.parameters.rcut = 4.5; @@ -43,7 +43,7 @@ ModuleMD::SNAP::ModelData make_multi_element_model() return model; } -ModuleMD::SNAP::ModelData make_chemical_model() +ModuleMD::SNAP::ModelData chem_model() { ModuleMD::SNAP::ModelData model; model.parameters.rcut = 4.5; @@ -67,7 +67,7 @@ ModuleMD::SNAP::ModelData make_chemical_model() return model; } -ModuleMD::SNAP::ModelData make_angular_quadratic_model() +ModuleMD::SNAP::ModelData quad_model() { ModuleMD::SNAP::ModelData model = make_model(); model.parameters.twojmax = 2; @@ -86,7 +86,7 @@ struct SmallCellResult std::array, 3> forces = {}; }; -SmallCellResult evaluate_small_cell(const ModuleMD::SNAP::Calculator& calculator, +SmallCellResult eval_cell(const ModuleMD::SNAP::Calculator& calculator, const std::array, 3>& positions) { SmallCellResult total; @@ -94,7 +94,7 @@ SmallCellResult evaluate_small_cell(const ModuleMD::SNAP::Calculator& calculator for (std::size_t center = 0; center < positions.size(); ++center) { std::vector neighbors; - std::vector neighbor_indices; + std::vector neigh_indices; for (std::size_t atom = 0; atom < positions.size(); ++atom) { if (atom == center) @@ -107,10 +107,10 @@ SmallCellResult evaluate_small_cell(const ModuleMD::SNAP::Calculator& calculator neighbor.z = positions[atom][2] - positions[center][2]; neighbor.cutoff_radius = 4.5; neighbors.push_back(neighbor); - neighbor_indices.push_back(atom); + neigh_indices.push_back(atom); } - const ModuleMD::SNAP::ForceResult result = calculator.compute_with_analytic_force(neighbors, 0); - accumulator.add(center, neighbor_indices, neighbors, result); + const ModuleMD::SNAP::ForceResult result = calculator.eval_force(neighbors, 0); + accumulator.add(center, neigh_indices, neighbors, result); } total.energy = accumulator.energy(); total.virial_xx = accumulator.virial()[0]; @@ -121,7 +121,7 @@ SmallCellResult evaluate_small_cell(const ModuleMD::SNAP::Calculator& calculator return total; } -TEST(SnapCalculator, ComputesLinearAtomicEnergy) +TEST(SnapCalculator, LinearEnergy) { const ModuleMD::SNAP::Calculator calculator(make_model()); ModuleMD::SNAP::Neighbor neighbor; @@ -134,9 +134,9 @@ TEST(SnapCalculator, ComputesLinearAtomicEnergy) EXPECT_DOUBLE_EQ(result.energy, 2.0 + 3.0 * result.descriptor[0]); } -TEST(SnapCalculator, SupportsMultipleCentralElements) +TEST(SnapCalculator, MultiCenter) { - const ModuleMD::SNAP::Calculator calculator(make_multi_element_model()); + const ModuleMD::SNAP::Calculator calculator(multi_model()); const std::vector neighbors; const ModuleMD::SNAP::EnergyResult silicon = calculator.compute(neighbors, 0); const ModuleMD::SNAP::EnergyResult carbon = calculator.compute(neighbors, 1); @@ -146,9 +146,9 @@ TEST(SnapCalculator, SupportsMultipleCentralElements) EXPECT_NE(silicon.energy, carbon.energy); } -TEST(SnapCalculator, SupportsChemicalChannels) +TEST(SnapCalculator, ChemChannel) { - const ModuleMD::SNAP::Calculator calculator(make_chemical_model()); + const ModuleMD::SNAP::Calculator calculator(chem_model()); ModuleMD::SNAP::Neighbor silicon; silicon.x = 1.0; silicon.cutoff_radius = 4.5; @@ -158,42 +158,42 @@ TEST(SnapCalculator, SupportsChemicalChannels) carbon.element_index = 1; const std::vector neighbors = {silicon, carbon}; - const ModuleMD::SNAP::ForceResult analytic = calculator.compute_with_analytic_force(neighbors, 0); - const ModuleMD::SNAP::ForceResult finite_difference - = calculator.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); + const ModuleMD::SNAP::ForceResult analytic = calculator.eval_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult finite_diff + = calculator.eval_force_fd(neighbors, 0, 1.0e-6); EXPECT_EQ(analytic.energy.descriptor.size(), static_cast(8)); - EXPECT_NEAR(analytic.energy.energy, finite_difference.energy.energy, 1.0e-12); + EXPECT_NEAR(analytic.energy.energy, finite_diff.energy.energy, 1.0e-12); for (int direction = 0; direction < 3; ++direction) { EXPECT_NEAR(analytic.center_force[static_cast(direction)], - finite_difference.center_force[static_cast(direction)], + finite_diff.center_force[static_cast(direction)], 1.0e-5); EXPECT_NEAR(analytic.neighbor_forces[0][static_cast(direction)], - finite_difference.neighbor_forces[0][static_cast(direction)], + finite_diff.neighbor_forces[0][static_cast(direction)], 1.0e-5); } } -TEST(SnapCalculator, RejectsMismatchedCoefficientCount) +TEST(SnapCalculator, BadCoeffCount) { ModuleMD::SNAP::ModelData model = make_model(); model.coefficients[0].push_back(4.0); EXPECT_THROW(ModuleMD::SNAP::Calculator calculator(model), std::invalid_argument); } -TEST(SnapCalculator, RejectsInvalidCentralElement) +TEST(SnapCalculator, BadCenter) { const ModuleMD::SNAP::Calculator calculator(make_model()); EXPECT_THROW(calculator.compute(std::vector(), 1), std::out_of_range); } -TEST(SnapCalculator, FiniteDifferenceForcesConservePairContribution) +TEST(SnapCalculator, PairBalance) { const ModuleMD::SNAP::Calculator calculator(make_model()); ModuleMD::SNAP::Neighbor neighbor; neighbor.x = 1.0; - const ModuleMD::SNAP::ForceResult result = calculator.compute_with_finite_difference_force( + const ModuleMD::SNAP::ForceResult result = calculator.eval_force_fd( std::vector(1, neighbor), 0, 1.0e-5); for (int direction = 0; direction < 3; ++direction) @@ -204,7 +204,7 @@ TEST(SnapCalculator, FiniteDifferenceForcesConservePairContribution) } } -TEST(SnapCalculator, AnalyticForceMatchesFiniteDifference) +TEST(SnapCalculator, ForceFinite) { const ModuleMD::SNAP::Calculator calculator(make_model()); ModuleMD::SNAP::Neighbor neighbor; @@ -212,8 +212,8 @@ TEST(SnapCalculator, AnalyticForceMatchesFiniteDifference) neighbor.y = 0.4; neighbor.z = -0.2; const std::vector neighbors(1, neighbor); - const ModuleMD::SNAP::ForceResult analytic = calculator.compute_with_analytic_force(neighbors, 0); - const ModuleMD::SNAP::ForceResult finite = calculator.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); + const ModuleMD::SNAP::ForceResult analytic = calculator.eval_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult finite = calculator.eval_force_fd(neighbors, 0, 1.0e-6); for (int direction = 0; direction < 3; ++direction) { EXPECT_NEAR(analytic.neighbor_forces[0][static_cast(direction)], @@ -222,11 +222,11 @@ TEST(SnapCalculator, AnalyticForceMatchesFiniteDifference) } } -TEST(SnapCalculator, InnerSwitchMatchesFiniteDifference) +TEST(SnapCalculator, InnerFinite) { ModuleMD::SNAP::ModelData model = make_model(); model.parameters.twojmax = 2; - model.parameters.switchinner_flag = true; + model.parameters.inner_flag = true; model.parameters.sinner.push_back(1.5); model.parameters.dinner.push_back(0.4); model.coefficients[0] = {0.2, 0.3, -0.1, 0.5, 0.2, -0.4}; @@ -242,8 +242,8 @@ TEST(SnapCalculator, InnerSwitchMatchesFiniteDifference) second.y = 1.7; second.z = -0.2; const std::vector neighbors = {first, second}; - const ModuleMD::SNAP::ForceResult analytic = calculator.compute_with_analytic_force(neighbors, 0); - const ModuleMD::SNAP::ForceResult finite = calculator.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); + const ModuleMD::SNAP::ForceResult analytic = calculator.eval_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult finite = calculator.eval_force_fd(neighbors, 0, 1.0e-6); for (std::size_t i = 0; i < neighbors.size(); ++i) { for (int direction = 0; direction < 3; ++direction) @@ -258,23 +258,23 @@ TEST(SnapCalculator, InnerSwitchMatchesFiniteDifference) model.coefficients[0][6] = 0.25; model.coefficients[0][10] = -0.15; const ModuleMD::SNAP::Calculator quadratic(model); - const ModuleMD::SNAP::ForceResult quadratic_analytic = quadratic.compute_with_analytic_force(neighbors, 0); - const ModuleMD::SNAP::ForceResult quadratic_finite = quadratic.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); + const ModuleMD::SNAP::ForceResult quad_analytic = quadratic.eval_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult quad_finite = quadratic.eval_force_fd(neighbors, 0, 1.0e-6); for (std::size_t i = 0; i < neighbors.size(); ++i) { for (int direction = 0; direction < 3; ++direction) { - EXPECT_NEAR(quadratic_analytic.neighbor_forces[i][static_cast(direction)], - quadratic_finite.neighbor_forces[i][static_cast(direction)], 1.0e-5); + EXPECT_NEAR(quad_analytic.neighbor_forces[i][static_cast(direction)], + quad_finite.neighbor_forces[i][static_cast(direction)], 1.0e-5); } } } -TEST(SnapCalculator, InnerSwitchSkipsSingularRadius) +TEST(SnapCalculator, InnerSkip) { ModuleMD::SNAP::ModelData model = make_model(); model.parameters.rmin = 0.5; - model.parameters.switchinner_flag = true; + model.parameters.inner_flag = true; model.parameters.sinner.push_back(1.5); model.parameters.dinner.push_back(0.4); const ModuleMD::SNAP::Calculator calculator(model); @@ -283,11 +283,11 @@ TEST(SnapCalculator, InnerSwitchSkipsSingularRadius) neighbor.sinner = 1.5; neighbor.dinner = 0.4; const std::vector neighbors(1, neighbor); - EXPECT_NO_THROW(calculator.compute_with_analytic_force(neighbors, 0)); - model.parameters.switchinner_flag = false; + EXPECT_NO_THROW(calculator.eval_force(neighbors, 0)); + model.parameters.inner_flag = false; const ModuleMD::SNAP::Calculator bare(model); EXPECT_THROW(bare.compute(neighbors, 0), std::domain_error); - EXPECT_THROW(bare.compute_with_analytic_force(neighbors, 0), std::domain_error); + EXPECT_THROW(bare.eval_force(neighbors, 0), std::domain_error); model.parameters.twojmax = 2; model.coefficients[0] = {0.2, 0.3, -0.1, 0.5, 0.2, -0.4}; @@ -295,8 +295,8 @@ TEST(SnapCalculator, InnerSwitchSkipsSingularRadius) neighbor.x = 0.55; neighbor.y = 0.12; const std::vector near_neighbors(1, neighbor); - const ModuleMD::SNAP::ForceResult near_analytic = angular.compute_with_analytic_force(near_neighbors, 0); - const ModuleMD::SNAP::ForceResult near_finite = angular.compute_with_finite_difference_force(near_neighbors, 0, 1.0e-6); + const ModuleMD::SNAP::ForceResult near_analytic = angular.eval_force(near_neighbors, 0); + const ModuleMD::SNAP::ForceResult near_finite = angular.eval_force_fd(near_neighbors, 0, 1.0e-6); EXPECT_TRUE(std::isfinite(near_analytic.energy.energy)); for (int direction = 0; direction < 3; ++direction) { @@ -306,13 +306,13 @@ TEST(SnapCalculator, InnerSwitchSkipsSingularRadius) } } -TEST(SnapCalculator, AngularQuadraticForcesMatchLammpsAndStrain) +TEST(SnapCalculator, QuadStrain) { - const ModuleMD::SNAP::Calculator calculator(make_angular_quadratic_model()); + const ModuleMD::SNAP::Calculator calculator(quad_model()); const std::array, 3> positions = {{{0.0, 0.0, 0.0}, {1.058354, 0.0, 0.0}, {0.2645885, 1.3229425, 0.0}}}; - const SmallCellResult result = evaluate_small_cell(calculator, positions); + const SmallCellResult result = eval_cell(calculator, positions); const double lammps_forces[3][2] = {{67.2928038408958, 57.5476436778783}, {-92.1399449575303, 60.5944497536836}, {24.8471411166345, -118.142093431562}}; @@ -334,10 +334,10 @@ TEST(SnapCalculator, AngularQuadraticForcesMatchLammpsAndStrain) expanded[atom][0] *= 1.0 + strain; contracted[atom][0] *= 1.0 - strain; } - const double expanded_energy = evaluate_small_cell(calculator, expanded).energy; - const double contracted_energy = evaluate_small_cell(calculator, contracted).energy; - const double strain_derivative = (expanded_energy - contracted_energy) / (2.0 * strain); - EXPECT_NEAR(result.virial_xx, -strain_derivative, 1.0e-3); + const double expanded_energy = eval_cell(calculator, expanded).energy; + const double strain_energy = eval_cell(calculator, contracted).energy; + const double strain_deriv = (expanded_energy - strain_energy) / (2.0 * strain); + EXPECT_NEAR(result.virial_xx, -strain_deriv, 1.0e-3); } } // namespace diff --git a/source/source_md/module_snap/unittests/test_cg.cpp b/source/source_md/module_snap/unittests/test_cg.cpp index 436d4a743f9..525650cb3e6 100644 --- a/source/source_md/module_snap/unittests/test_cg.cpp +++ b/source/source_md/module_snap/unittests/test_cg.cpp @@ -7,23 +7,23 @@ namespace { -TEST(SnapClebschGordan, HighestWeightCoefficientIsOne) +TEST(SnapCG, HighWeight) { - const ModuleMD::SNAP::ClebschGordanTable table(2); + const ModuleMD::SNAP::CGTable table(2); EXPECT_NEAR(table.coefficient(1, 1, 1, 1, 2, 2), 1.0, 1.0e-14); } -TEST(SnapClebschGordan, SingletHasExpectedSigns) +TEST(SnapCG, SingletSigns) { - const ModuleMD::SNAP::ClebschGordanTable table(2); + const ModuleMD::SNAP::CGTable table(2); const double value = 1.0 / std::sqrt(2.0); EXPECT_NEAR(table.coefficient(1, 1, 1, -1, 0, 0), value, 1.0e-14); EXPECT_NEAR(table.coefficient(1, -1, 1, 1, 0, 0), -value, 1.0e-14); } -TEST(SnapClebschGordan, SelectionRulesReturnZero) +TEST(SnapCG, SelectZero) { - const ModuleMD::SNAP::ClebschGordanTable table(2); + const ModuleMD::SNAP::CGTable table(2); EXPECT_DOUBLE_EQ(table.coefficient(1, 1, 1, 1, 0, 0), 0.0); EXPECT_DOUBLE_EQ(table.coefficient(1, 1, 1, -1, 2, 1), 0.0); EXPECT_DOUBLE_EQ(table.h_coefficient(1, 1, 1, 1, -1, -1, 0, 0, 0), 0.5); diff --git a/source/source_md/module_snap/unittests/test_desc.cpp b/source/source_md/module_snap/unittests/test_desc.cpp index eedd5f56dd8..c4e206745ed 100644 --- a/source/source_md/module_snap/unittests/test_desc.cpp +++ b/source/source_md/module_snap/unittests/test_desc.cpp @@ -22,16 +22,16 @@ ModuleMD::SNAP::ModelParameters make_parameters() return parameters; } -TEST(SnapDescriptor, AllocatesExpectedArraySizes) +TEST(SnapDescriptor, ArraySizes) { - const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); + const ModuleMD::SNAP::DescEval evaluator(make_parameters()); EXPECT_EQ(evaluator.u_size(), static_cast(1 * 1 + 2 * 2 + 3 * 3)); EXPECT_EQ(evaluator.bispectrum_size(), static_cast(5)); } -TEST(SnapDescriptor, SelfContributionIsDiagonal) +TEST(SnapDescriptor, SelfDiagonal) { - const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); + const ModuleMD::SNAP::DescEval evaluator(make_parameters()); const std::vector neighbors; const std::vector > u = evaluator.accumulate_u(neighbors); @@ -43,9 +43,9 @@ TEST(SnapDescriptor, SelfContributionIsDiagonal) EXPECT_DOUBLE_EQ(u[13].imag(), 0.0); } -TEST(SnapDescriptor, OutsideCutoffDoesNotChangeEnvironment) +TEST(SnapDescriptor, OutsideCutoff) { - const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); + const ModuleMD::SNAP::DescEval evaluator(make_parameters()); ModuleMD::SNAP::Neighbor neighbor; neighbor.x = 5.0; const std::vector neighbors(1, neighbor); @@ -60,15 +60,15 @@ TEST(SnapDescriptor, OutsideCutoffDoesNotChangeEnvironment) } } -TEST(SnapDescriptor, BispectrumIsFinite) +TEST(SnapDescriptor, FiniteBispec) { - const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); + const ModuleMD::SNAP::DescEval evaluator(make_parameters()); ModuleMD::SNAP::Neighbor neighbor; neighbor.x = 1.2; neighbor.y = 0.4; neighbor.z = -0.8; const std::vector > u = evaluator.accumulate_u(std::vector(1, neighbor)); - const std::vector bispectrum = evaluator.compute_bispectrum(u); + const std::vector bispectrum = evaluator.calc_bispec(u); for (std::size_t i = 0; i < bispectrum.size(); ++i) { @@ -76,9 +76,9 @@ TEST(SnapDescriptor, BispectrumIsFinite) } } -TEST(SnapDescriptor, MatchesLammpsSingleElementReference) +TEST(SnapDescriptor, LammpsValue) { - const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); + const ModuleMD::SNAP::DescEval evaluator(make_parameters()); const double positions[3][3] = {{1.0, 1.0, 1.0}, {2.0, 1.0, 1.0}, {1.0, 3.0, 1.0}}; std::vector neighbors; for (int atom = 1; atom < 3; ++atom) @@ -90,7 +90,7 @@ TEST(SnapDescriptor, MatchesLammpsSingleElementReference) neighbor.cutoff_radius = 4.0; neighbors.push_back(neighbor); } - const std::vector bispectrum = evaluator.compute_bispectrum(evaluator.accumulate_u(neighbors)); + const std::vector bispectrum = evaluator.calc_bispec(evaluator.accumulate_u(neighbors)); const double reference[5] = { 13.0368348609, 15.0992648922, 11.7631725456, 13.7069739819, 6.07477849248}; ASSERT_EQ(bispectrum.size(), static_cast(5)); diff --git a/source/source_md/module_snap/unittests/test_model.cpp b/source/source_md/module_snap/unittests/test_model.cpp index a697978dda4..81cff30940f 100644 --- a/source/source_md/module_snap/unittests/test_model.cpp +++ b/source/source_md/module_snap/unittests/test_model.cpp @@ -8,7 +8,7 @@ namespace { -TEST(SnapModel, AcceptsCompleteParameters) +TEST(SnapModel, ValidParams) { ModuleMD::SNAP::ModelParameters parameters; parameters.rcut = 4.5; @@ -25,7 +25,7 @@ TEST(SnapModel, AcceptsCompleteParameters) EXPECT_TRUE(error.empty()); } -TEST(SnapModel, RejectsInconsistentElementData) +TEST(SnapModel, BadElements) { ModuleMD::SNAP::ModelParameters parameters; parameters.rcut = 4.5; @@ -40,7 +40,7 @@ TEST(SnapModel, RejectsInconsistentElementData) EXPECT_FALSE(error.empty()); } -TEST(SnapModel, RejectsInvalidRadialRange) +TEST(SnapModel, BadRadial) { ModuleMD::SNAP::ModelParameters parameters; parameters.rcut = 3.0; @@ -56,7 +56,7 @@ TEST(SnapModel, RejectsInvalidRadialRange) EXPECT_FALSE(error.empty()); } -TEST(SnapModel, RejectsRminOutsideSmallPairCutoff) +TEST(SnapModel, BadPairCutoff) { ModuleMD::SNAP::ModelParameters parameters; parameters.rcut = 4.0; @@ -71,12 +71,12 @@ TEST(SnapModel, RejectsRminOutsideSmallPairCutoff) EXPECT_NE(error.find("Small-Small"), std::string::npos); } -TEST(SnapModel, LoadsLammpsStyleCoefficientAndParameterFiles) +TEST(SnapModel, LoadLammps) { - const std::string coefficient_file = testing::TempDir() + "snap_coeff_test.txt"; + const std::string coeff_file = testing::TempDir() + "snap_coeff_test.txt"; const std::string parameter_file = testing::TempDir() + "snap_param_test.txt"; { - std::ofstream output(coefficient_file.c_str()); + std::ofstream output(coeff_file.c_str()); output << "1 3\n"; output << "Si 2.25 1.0\n"; output << "-0.5\n1.25\n2.5\n"; @@ -93,24 +93,24 @@ TEST(SnapModel, LoadsLammpsStyleCoefficientAndParameterFiles) ModuleMD::SNAP::ModelData model; std::string error; - EXPECT_TRUE(model.load(coefficient_file, parameter_file, std::vector(1, "Si"), error)); + EXPECT_TRUE(model.load(coeff_file, parameter_file, std::vector(1, "Si"), error)); EXPECT_TRUE(error.empty()); - ASSERT_EQ(model.coefficient_count(), static_cast(3)); + ASSERT_EQ(model.coeff_count(), static_cast(3)); EXPECT_DOUBLE_EQ(model.parameters.element_weights[0], 1.0); EXPECT_DOUBLE_EQ(model.parameters.element_radii[0], 2.25); EXPECT_DOUBLE_EQ(model.parameters.rcut, 5.4); EXPECT_DOUBLE_EQ(model.coefficients[0][1], 1.25); - std::remove(coefficient_file.c_str()); + std::remove(coeff_file.c_str()); std::remove(parameter_file.c_str()); } -TEST(SnapModel, LoadsMultipleElementBlocks) +TEST(SnapModel, MultiBlocks) { - const std::string coefficient_file = testing::TempDir() + "snap_coeff_multi_test.txt"; - const std::string parameter_file = testing::TempDir() + "snap_param_multi_test.txt"; + const std::string coeff_file = testing::TempDir() + "coeff_multi.txt"; + const std::string parameter_file = testing::TempDir() + "param_multi.txt"; { - std::ofstream output(coefficient_file.c_str()); + std::ofstream output(coeff_file.c_str()); output << "2 2\n"; output << "Si 2.25 1.0\n"; output << "-0.5\n1.25\n"; @@ -129,23 +129,23 @@ TEST(SnapModel, LoadsMultipleElementBlocks) ModuleMD::SNAP::ModelData model; std::string error; const std::vector elements = {"Si", "C"}; - EXPECT_TRUE(model.load(coefficient_file, parameter_file, elements, error)); + EXPECT_TRUE(model.load(coeff_file, parameter_file, elements, error)); EXPECT_TRUE(error.empty()); ASSERT_EQ(model.coefficients.size(), static_cast(2)); EXPECT_DOUBLE_EQ(model.parameters.element_weights[1], 0.8); EXPECT_DOUBLE_EQ(model.parameters.element_radii[1], 1.7); EXPECT_DOUBLE_EQ(model.coefficients[1][1], 2.5); - std::remove(coefficient_file.c_str()); + std::remove(coeff_file.c_str()); std::remove(parameter_file.c_str()); } -TEST(SnapModel, LoadsChemicalCoefficientBlocks) +TEST(SnapModel, ChemBlocks) { - const std::string coefficient_file = testing::TempDir() + "snap_coeff_chemical_test.txt"; - const std::string parameter_file = testing::TempDir() + "snap_param_chemical_test.txt"; + const std::string coeff_file = testing::TempDir() + "coeff_chem.txt"; + const std::string parameter_file = testing::TempDir() + "param_chem.txt"; { - std::ofstream output(coefficient_file.c_str()); + std::ofstream output(coeff_file.c_str()); output << "2 9\n"; output << "Si 2.25 1.0\n"; for (int i = 0; i < 9; ++i) @@ -172,31 +172,31 @@ TEST(SnapModel, LoadsChemicalCoefficientBlocks) ModuleMD::SNAP::ModelData model; std::string error; const std::vector elements = {"Si", "C"}; - EXPECT_TRUE(model.load(coefficient_file, parameter_file, elements, error)); + EXPECT_TRUE(model.load(coeff_file, parameter_file, elements, error)); EXPECT_TRUE(error.empty()); ASSERT_EQ(model.coefficients.size(), static_cast(2)); EXPECT_TRUE(model.parameters.chem_flag); EXPECT_EQ(model.coefficients[0].size(), static_cast(9)); EXPECT_DOUBLE_EQ(model.coefficients[1][1], 2.0); - const std::vector reversed_elements = {"C", "Si"}; + const std::vector rev_elements = {"C", "Si"}; ModuleMD::SNAP::ModelData reversed; - ASSERT_TRUE(reversed.load(coefficient_file, parameter_file, reversed_elements, error)) << error; + ASSERT_TRUE(reversed.load(coeff_file, parameter_file, rev_elements, error)) << error; EXPECT_EQ(reversed.parameters.elements[0], "C"); EXPECT_EQ(reversed.parameters.elements[1], "Si"); EXPECT_DOUBLE_EQ(reversed.coefficients[0][1], 2.0); EXPECT_DOUBLE_EQ(reversed.coefficients[1][1], 1.0); - std::remove(coefficient_file.c_str()); + std::remove(coeff_file.c_str()); std::remove(parameter_file.c_str()); } -TEST(SnapModel, ReadsInnerSwitchAndRejectsUnknownParameter) +TEST(SnapModel, InnerOptions) { - const std::string coefficient_file = testing::TempDir() + "snap_inner_coeff.txt"; - const std::string parameter_file = testing::TempDir() + "snap_inner_param.txt"; + const std::string coeff_file = testing::TempDir() + "inner_coeff.txt"; + const std::string parameter_file = testing::TempDir() + "inner_param.txt"; { - std::ofstream output(coefficient_file.c_str()); + std::ofstream output(coeff_file.c_str()); output << "1 2\nSi 2.0 1.0\n0.0\n1.0\n"; } { @@ -207,30 +207,30 @@ TEST(SnapModel, ReadsInnerSwitchAndRejectsUnknownParameter) ModuleMD::SNAP::ModelData model; std::string error; const std::vector elements(1, "Si"); - ASSERT_TRUE(model.load(coefficient_file, parameter_file, elements, error)) << error; - EXPECT_TRUE(model.parameters.switchinner_flag); + ASSERT_TRUE(model.load(coeff_file, parameter_file, elements, error)) << error; + EXPECT_TRUE(model.parameters.inner_flag); ASSERT_EQ(model.parameters.sinner.size(), static_cast(1)); EXPECT_DOUBLE_EQ(model.parameters.sinner[0], 1.5); { std::ofstream output(parameter_file.c_str(), std::ios::app); - output << "unsupported_option 1\n"; + output << "bad_option 1\n"; } - EXPECT_FALSE(model.load(coefficient_file, parameter_file, elements, error)); - EXPECT_NE(error.find("unsupported_option"), std::string::npos); + EXPECT_FALSE(model.load(coeff_file, parameter_file, elements, error)); + EXPECT_NE(error.find("bad_option"), std::string::npos); { std::ofstream output(parameter_file.c_str()); output << "rcutfac 1.0\ntwojmax 0\nswitchinnerflag 1\nsinner 1.5\n"; } error.clear(); - EXPECT_FALSE(model.load(coefficient_file, parameter_file, elements, error)); + EXPECT_FALSE(model.load(coeff_file, parameter_file, elements, error)); EXPECT_NE(error.find("requires sinner and dinner"), std::string::npos); { std::ofstream output(parameter_file.c_str()); output << "rcutfac 1.0\ntwojmax 0\nswitchinnerflag 0\n"; } error.clear(); - EXPECT_TRUE(model.load(coefficient_file, parameter_file, elements, error)) << error; - std::remove(coefficient_file.c_str()); + EXPECT_TRUE(model.load(coeff_file, parameter_file, elements, error)) << error; + std::remove(coeff_file.c_str()); std::remove(parameter_file.c_str()); } From b7c780bfcafd5ae76a2e7e6e9ac949b15e230ff3 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 13:26:55 +0800 Subject: [PATCH 21/33] fix: report SNAP evaluation errors through WARNING_QUIT --- source/source_esolver/snap_solver.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/source_esolver/snap_solver.cpp b/source/source_esolver/snap_solver.cpp index 0311c01307c..7c2290c9553 100644 --- a/source/source_esolver/snap_solver.cpp +++ b/source/source_esolver/snap_solver.cpp @@ -110,7 +110,7 @@ void ESolver_SNAP::before_all_runners(BaseCell& cell, const Input_para& inp) snap_force_.create(ucell.nat, 3); } -void ESolver_SNAP::runner(BaseCell& cell, const int istep) +void ESolver_SNAP::runner(BaseCell& cell, const int istep) try { static_cast(istep); if (!calculator_) @@ -244,6 +244,11 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) } } } +catch (const std::exception& error) +{ + const std::string message = std::string("SNAP evaluation failed: ") + error.what(); + fail(message); +} double ESolver_SNAP::cal_energy() { From 8def046b208deed2afd0cb06f0981cb8d4753e83 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 13:35:00 +0800 Subject: [PATCH 22/33] test: name SNAP model fixtures for each regression case --- tests/04_FF/102_SNAP_base/INPUT | 4 +- tests/04_FF/102_SNAP_base/README | 5 +- tests/04_FF/103_SNAP_pbc/INPUT | 4 +- tests/04_FF/103_SNAP_pbc/README | 3 + tests/04_FF/104_SNAP_inner/INPUT | 4 +- tests/04_FF/104_SNAP_inner/README | 3 + tests/04_FF/105_SNAP_quad/INPUT | 4 +- tests/04_FF/105_SNAP_quad/README | 3 + tests/04_FF/106_SNAP_scf/INPUT | 4 +- tests/04_FF/106_SNAP_scf/README | 3 + .../{snap1.coeff => snap_102_base.coeff} | 0 .../{snap1.param => snap_102_base.param} | 0 tests/SIMULATION_MODELS/snap_103_pbc.coeff | 62 +++++++++++++++++++ tests/SIMULATION_MODELS/snap_103_pbc.param | 10 +++ tests/SIMULATION_MODELS/snap_104_inner.coeff | 62 +++++++++++++++++++ .../{snap2.param => snap_104_inner.param} | 0 .../{snap3.coeff => snap_105_quad.coeff} | 0 .../{snap3.param => snap_105_quad.param} | 0 tests/SIMULATION_MODELS/snap_106_scf.coeff | 24 +++++++ tests/SIMULATION_MODELS/snap_106_scf.param | 6 ++ 20 files changed, 189 insertions(+), 12 deletions(-) rename tests/SIMULATION_MODELS/{snap1.coeff => snap_102_base.coeff} (100%) rename tests/SIMULATION_MODELS/{snap1.param => snap_102_base.param} (100%) create mode 100644 tests/SIMULATION_MODELS/snap_103_pbc.coeff create mode 100644 tests/SIMULATION_MODELS/snap_103_pbc.param create mode 100644 tests/SIMULATION_MODELS/snap_104_inner.coeff rename tests/SIMULATION_MODELS/{snap2.param => snap_104_inner.param} (100%) rename tests/SIMULATION_MODELS/{snap3.coeff => snap_105_quad.coeff} (100%) rename tests/SIMULATION_MODELS/{snap3.param => snap_105_quad.param} (100%) create mode 100644 tests/SIMULATION_MODELS/snap_106_scf.coeff create mode 100644 tests/SIMULATION_MODELS/snap_106_scf.param diff --git a/tests/04_FF/102_SNAP_base/INPUT b/tests/04_FF/102_SNAP_base/INPUT index 7d3649f6962..1928e9e50a2 100644 --- a/tests/04_FF/102_SNAP_base/INPUT +++ b/tests/04_FF/102_SNAP_base/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file ../../SIMULATION_MODELS/snap1.coeff -snap_param_file ../../SIMULATION_MODELS/snap1.param +pot_file ../../SIMULATION_MODELS/snap_102_base.coeff +snap_param_file ../../SIMULATION_MODELS/snap_102_base.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/102_SNAP_base/README b/tests/04_FF/102_SNAP_base/README index 4038675f701..ac442ea4791 100644 --- a/tests/04_FF/102_SNAP_base/README +++ b/tests/04_FF/102_SNAP_base/README @@ -1,7 +1,8 @@ CPU SNAP regression case with a two-atom Si periodic structure. -The example uses `../../SIMULATION_MODELS/snap1.coeff` for the SNAP coefficients and `../../SIMULATION_MODELS/snap1.param` for -the SNAP parameters. +The example uses `../../SIMULATION_MODELS/snap_102_base.coeff` for the SNAP +coefficients and `../../SIMULATION_MODELS/snap_102_base.param` for the SNAP +parameters. The coefficient and parameter files are deterministic ABACUS-generated test fixtures. They are intended only to exercise SNAP parsing, energy, force, and diff --git a/tests/04_FF/103_SNAP_pbc/INPUT b/tests/04_FF/103_SNAP_pbc/INPUT index 7d3649f6962..f052d2967da 100644 --- a/tests/04_FF/103_SNAP_pbc/INPUT +++ b/tests/04_FF/103_SNAP_pbc/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file ../../SIMULATION_MODELS/snap1.coeff -snap_param_file ../../SIMULATION_MODELS/snap1.param +pot_file ../../SIMULATION_MODELS/snap_103_pbc.coeff +snap_param_file ../../SIMULATION_MODELS/snap_103_pbc.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/103_SNAP_pbc/README b/tests/04_FF/103_SNAP_pbc/README index 1d835070432..9c3dc25e7d9 100644 --- a/tests/04_FF/103_SNAP_pbc/README +++ b/tests/04_FF/103_SNAP_pbc/README @@ -4,3 +4,6 @@ This uses the same potential and two-atom separation as 102_SNAP_base, but places the atoms on opposite sides of the periodic boundary. Their energy, force magnitude, and stress must match the unwrapped case. The periodic neighbor contributes through the MDCell ghost-force return path. + +Model files: ../../SIMULATION_MODELS/snap_103_pbc.coeff and +../../SIMULATION_MODELS/snap_103_pbc.param. diff --git a/tests/04_FF/104_SNAP_inner/INPUT b/tests/04_FF/104_SNAP_inner/INPUT index 93c3bd9f381..aa3f97ef195 100644 --- a/tests/04_FF/104_SNAP_inner/INPUT +++ b/tests/04_FF/104_SNAP_inner/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file ../../SIMULATION_MODELS/snap1.coeff -snap_param_file ../../SIMULATION_MODELS/snap2.param +pot_file ../../SIMULATION_MODELS/snap_104_inner.coeff +snap_param_file ../../SIMULATION_MODELS/snap_104_inner.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/104_SNAP_inner/README b/tests/04_FF/104_SNAP_inner/README index 8c436ba5c3c..af552b75e40 100644 --- a/tests/04_FF/104_SNAP_inner/README +++ b/tests/04_FF/104_SNAP_inner/README @@ -8,3 +8,6 @@ software-test fixture, not a validated physical potential. The reference was cross-checked with LAMMPS SNAP (30 Mar 2026 development build, c46bbef): potential energy -0.24612388 eV, x forces -2.7962 and +2.7962 eV/Angstrom, and Pxx 3999.6081 bar. ABACUS reports Pxx in kbar. + +Model files: ../../SIMULATION_MODELS/snap_104_inner.coeff and +../../SIMULATION_MODELS/snap_104_inner.param. diff --git a/tests/04_FF/105_SNAP_quad/INPUT b/tests/04_FF/105_SNAP_quad/INPUT index dfa30068bed..0ec21aca421 100644 --- a/tests/04_FF/105_SNAP_quad/INPUT +++ b/tests/04_FF/105_SNAP_quad/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file ../../SIMULATION_MODELS/snap3.coeff -snap_param_file ../../SIMULATION_MODELS/snap3.param +pot_file ../../SIMULATION_MODELS/snap_105_quad.coeff +snap_param_file ../../SIMULATION_MODELS/snap_105_quad.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/105_SNAP_quad/README b/tests/04_FF/105_SNAP_quad/README index 81aa415ee92..bd87be609d0 100644 --- a/tests/04_FF/105_SNAP_quad/README +++ b/tests/04_FF/105_SNAP_quad/README @@ -8,3 +8,6 @@ LAMMPS (30 Mar 2026 development build, c46bbef) gives total potential energy (-92.139945, 60.594450, 0), and (24.847141, -118.142093, 0), and Pxx -122909.08 bar. ABACUS reports stress in kbar. The calculator unit test checks each force component and compares virial with an energy strain derivative. + +Model files: ../../SIMULATION_MODELS/snap_105_quad.coeff and +../../SIMULATION_MODELS/snap_105_quad.param. diff --git a/tests/04_FF/106_SNAP_scf/INPUT b/tests/04_FF/106_SNAP_scf/INPUT index 52fca03b771..f4a345fbac3 100644 --- a/tests/04_FF/106_SNAP_scf/INPUT +++ b/tests/04_FF/106_SNAP_scf/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation scf suffix autotest esolver_type snap -pot_file ../../SIMULATION_MODELS/snap3.coeff -snap_param_file ../../SIMULATION_MODELS/snap3.param +pot_file ../../SIMULATION_MODELS/snap_106_scf.coeff +snap_param_file ../../SIMULATION_MODELS/snap_106_scf.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/106_SNAP_scf/README b/tests/04_FF/106_SNAP_scf/README index 0bc0b1ac1aa..fdeb4b03861 100644 --- a/tests/04_FF/106_SNAP_scf/README +++ b/tests/04_FF/106_SNAP_scf/README @@ -2,3 +2,6 @@ UnitCell SNAP single-point regression using the same angular and quadratic model as case 105. The calculation enters the UnitCell solver path rather than the direct MDCell path. Energy, total force, and stress must match case 105 and the LAMMPS reference described there. + +Model files: ../../SIMULATION_MODELS/snap_106_scf.coeff and +../../SIMULATION_MODELS/snap_106_scf.param. diff --git a/tests/SIMULATION_MODELS/snap1.coeff b/tests/SIMULATION_MODELS/snap_102_base.coeff similarity index 100% rename from tests/SIMULATION_MODELS/snap1.coeff rename to tests/SIMULATION_MODELS/snap_102_base.coeff diff --git a/tests/SIMULATION_MODELS/snap1.param b/tests/SIMULATION_MODELS/snap_102_base.param similarity index 100% rename from tests/SIMULATION_MODELS/snap1.param rename to tests/SIMULATION_MODELS/snap_102_base.param diff --git a/tests/SIMULATION_MODELS/snap_103_pbc.coeff b/tests/SIMULATION_MODELS/snap_103_pbc.coeff new file mode 100644 index 00000000000..fc13f2f7b43 --- /dev/null +++ b/tests/SIMULATION_MODELS/snap_103_pbc.coeff @@ -0,0 +1,62 @@ +# ABACUS-generated SNAP regression fixture +# This deterministic coefficient set is created for software testing only. +# It is not a transferable or physically validated material potential. + +1 56 +Si 0.5 1 +0.125000000000 +-0.002000000000 +0.003000000000 +-0.004000000000 +0.005000000000 +-0.006000000000 +0.007000000000 +-0.008000000000 +0.009000000000 +-0.010000000000 +0.011000000000 +-0.012000000000 +0.013000000000 +-0.014000000000 +0.015000000000 +-0.016000000000 +0.017000000000 +-0.018000000000 +0.019000000000 +-0.020000000000 +0.021000000000 +-0.022000000000 +0.023000000000 +-0.024000000000 +0.025000000000 +-0.026000000000 +0.027000000000 +-0.028000000000 +0.029000000000 +-0.030000000000 +0.031000000000 +-0.032000000000 +0.033000000000 +-0.034000000000 +0.035000000000 +-0.036000000000 +0.037000000000 +-0.038000000000 +0.039000000000 +-0.040000000000 +0.041000000000 +-0.042000000000 +0.043000000000 +-0.044000000000 +0.045000000000 +-0.046000000000 +0.047000000000 +-0.048000000000 +0.049000000000 +-0.050000000000 +0.051000000000 +-0.052000000000 +0.053000000000 +-0.054000000000 +0.055000000000 +-0.056000000000 diff --git a/tests/SIMULATION_MODELS/snap_103_pbc.param b/tests/SIMULATION_MODELS/snap_103_pbc.param new file mode 100644 index 00000000000..23e0d83d38b --- /dev/null +++ b/tests/SIMULATION_MODELS/snap_103_pbc.param @@ -0,0 +1,10 @@ +# ABACUS-generated SNAP regression fixture +# This deterministic parameter set is created for software testing only. +# It is not a transferable or physically validated material potential. + +rcutfac 4.9 +twojmax 8 +rfac0 0.99363 +rmin0 0 +quadraticflag 0 +bzeroflag 0 diff --git a/tests/SIMULATION_MODELS/snap_104_inner.coeff b/tests/SIMULATION_MODELS/snap_104_inner.coeff new file mode 100644 index 00000000000..fc13f2f7b43 --- /dev/null +++ b/tests/SIMULATION_MODELS/snap_104_inner.coeff @@ -0,0 +1,62 @@ +# ABACUS-generated SNAP regression fixture +# This deterministic coefficient set is created for software testing only. +# It is not a transferable or physically validated material potential. + +1 56 +Si 0.5 1 +0.125000000000 +-0.002000000000 +0.003000000000 +-0.004000000000 +0.005000000000 +-0.006000000000 +0.007000000000 +-0.008000000000 +0.009000000000 +-0.010000000000 +0.011000000000 +-0.012000000000 +0.013000000000 +-0.014000000000 +0.015000000000 +-0.016000000000 +0.017000000000 +-0.018000000000 +0.019000000000 +-0.020000000000 +0.021000000000 +-0.022000000000 +0.023000000000 +-0.024000000000 +0.025000000000 +-0.026000000000 +0.027000000000 +-0.028000000000 +0.029000000000 +-0.030000000000 +0.031000000000 +-0.032000000000 +0.033000000000 +-0.034000000000 +0.035000000000 +-0.036000000000 +0.037000000000 +-0.038000000000 +0.039000000000 +-0.040000000000 +0.041000000000 +-0.042000000000 +0.043000000000 +-0.044000000000 +0.045000000000 +-0.046000000000 +0.047000000000 +-0.048000000000 +0.049000000000 +-0.050000000000 +0.051000000000 +-0.052000000000 +0.053000000000 +-0.054000000000 +0.055000000000 +-0.056000000000 diff --git a/tests/SIMULATION_MODELS/snap2.param b/tests/SIMULATION_MODELS/snap_104_inner.param similarity index 100% rename from tests/SIMULATION_MODELS/snap2.param rename to tests/SIMULATION_MODELS/snap_104_inner.param diff --git a/tests/SIMULATION_MODELS/snap3.coeff b/tests/SIMULATION_MODELS/snap_105_quad.coeff similarity index 100% rename from tests/SIMULATION_MODELS/snap3.coeff rename to tests/SIMULATION_MODELS/snap_105_quad.coeff diff --git a/tests/SIMULATION_MODELS/snap3.param b/tests/SIMULATION_MODELS/snap_105_quad.param similarity index 100% rename from tests/SIMULATION_MODELS/snap3.param rename to tests/SIMULATION_MODELS/snap_105_quad.param diff --git a/tests/SIMULATION_MODELS/snap_106_scf.coeff b/tests/SIMULATION_MODELS/snap_106_scf.coeff new file mode 100644 index 00000000000..aa7b790cd3f --- /dev/null +++ b/tests/SIMULATION_MODELS/snap_106_scf.coeff @@ -0,0 +1,24 @@ +# Deterministic software-test coefficients for angular and quadratic SNAP. +1 21 +Si 2.25 1.0 +0.2 +0.3 +-0.1 +0.5 +0.2 +-0.4 +0.25 +0.0 +0.0 +0.0 +-0.15 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 diff --git a/tests/SIMULATION_MODELS/snap_106_scf.param b/tests/SIMULATION_MODELS/snap_106_scf.param new file mode 100644 index 00000000000..eebdca8cf58 --- /dev/null +++ b/tests/SIMULATION_MODELS/snap_106_scf.param @@ -0,0 +1,6 @@ +rcutfac 1.0 +twojmax 2 +rfac0 0.99363 +rmin0 0.0 +quadraticflag 1 +bzeroflag 1 From c784e446acd48aa4bb522e62f49504f23eb8ddb6 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 13:36:58 +0800 Subject: [PATCH 23/33] refactor: restore descriptive SNAP source naming --- source/Makefile.Objects | 12 +-- source/source_esolver/CMakeLists.txt | 2 +- source/source_esolver/esolver_factory.cpp | 2 +- .../{snap_solver.cpp => esolver_snap.cpp} | 26 ++--- .../{snap_solver.h => esolver_snap.h} | 6 +- source/source_md/module_snap/CMakeLists.txt | 12 +-- .../{calc.cpp => snap_calculator.cpp} | 52 +++++----- .../module_snap/{calc.h => snap_calculator.h} | 22 ++--- .../{cg.cpp => snap_clebsch_gordan.cpp} | 18 ++-- .../{cg.h => snap_clebsch_gordan.h} | 12 +-- .../{deriv.cpp => snap_derivative.cpp} | 4 +- .../{desc.cpp => snap_descriptor.cpp} | 40 ++++---- .../module_snap/{desc.h => snap_descriptor.h} | 26 ++--- .../module_snap/{model.cpp => snap_model.cpp} | 68 ++++++------- .../module_snap/{model.h => snap_model.h} | 8 +- .../module_snap/unittest/CMakeLists.txt | 21 ++++ .../test_snap_calculator.cpp} | 98 +++++++++---------- .../test_snap_clebsch_gordan.cpp} | 14 +-- .../test_snap_descriptor.cpp} | 26 ++--- .../test_snap_model.cpp} | 74 +++++++------- .../module_snap/unittests/CMakeLists.txt | 21 ---- 21 files changed, 282 insertions(+), 282 deletions(-) rename source/source_esolver/{snap_solver.cpp => esolver_snap.cpp} (93%) rename source/source_esolver/{snap_solver.h => esolver_snap.h} (88%) rename source/source_md/module_snap/{calc.cpp => snap_calculator.cpp} (79%) rename source/source_md/module_snap/{calc.h => snap_calculator.h} (73%) rename source/source_md/module_snap/{cg.cpp => snap_clebsch_gordan.cpp} (90%) rename source/source_md/module_snap/{cg.h => snap_clebsch_gordan.h} (81%) rename source/source_md/module_snap/{deriv.cpp => snap_derivative.cpp} (97%) rename source/source_md/module_snap/{desc.cpp => snap_descriptor.cpp} (92%) rename source/source_md/module_snap/{desc.h => snap_descriptor.h} (72%) rename source/source_md/module_snap/{model.cpp => snap_model.cpp} (83%) rename source/source_md/module_snap/{model.h => snap_model.h} (83%) create mode 100644 source/source_md/module_snap/unittest/CMakeLists.txt rename source/source_md/module_snap/{unittests/test_calc.cpp => unittest/test_snap_calculator.cpp} (73%) rename source/source_md/module_snap/{unittests/test_cg.cpp => unittest/test_snap_clebsch_gordan.cpp} (60%) rename source/source_md/module_snap/{unittests/test_desc.cpp => unittest/test_snap_descriptor.cpp} (76%) rename source/source_md/module_snap/{unittests/test_model.cpp => unittest/test_snap_model.cpp} (70%) delete mode 100644 source/source_md/module_snap/unittests/CMakeLists.txt diff --git a/source/Makefile.Objects b/source/Makefile.Objects index f4ac6ec707c..24c03c90d0b 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -337,7 +337,7 @@ OBJS_ESOLVER=esolver_factory.o\ esolver_lj.o\ esolver_dp.o\ esolver_nep.o\ - snap_solver.o\ + esolver_snap.o\ esolver_of.o\ esolver_of_tddft.o\ esolver_of_interface.o\ @@ -538,11 +538,11 @@ OBJS_MD=fire.o\ nhchain.o\ plumed_interface.o\ run_md.o\ - module_snap/calc.o\ - module_snap/desc.o\ - module_snap/deriv.o\ - module_snap/model.o\ - module_snap/cg.o\ + module_snap/snap_calculator.o\ + module_snap/snap_descriptor.o\ + module_snap/snap_derivative.o\ + module_snap/snap_model.o\ + module_snap/snap_clebsch_gordan.o\ verlet.o\ OBJS_NEIGHBOR=sltk_atom.o\ diff --git a/source/source_esolver/CMakeLists.txt b/source/source_esolver/CMakeLists.txt index 5cd61aceb5d..3ccfe94f3bd 100644 --- a/source/source_esolver/CMakeLists.txt +++ b/source/source_esolver/CMakeLists.txt @@ -9,7 +9,7 @@ list(APPEND objects esolver_lj.cpp esolver_dp.cpp esolver_nep.cpp - snap_solver.cpp + esolver_snap.cpp esolver_of.cpp esolver_of_tddft.cpp esolver_of_interface.cpp diff --git a/source/source_esolver/esolver_factory.cpp b/source/source_esolver/esolver_factory.cpp index 76c4e2b0fc8..d69af4ac73a 100644 --- a/source/source_esolver/esolver_factory.cpp +++ b/source/source_esolver/esolver_factory.cpp @@ -24,7 +24,7 @@ #endif #include "esolver_dp.h" #include "esolver_nep.h" -#include "snap_solver.h" +#include "esolver_snap.h" #include "esolver_lj.h" #include "esolver_of.h" #include "esolver_of_tddft.h" diff --git a/source/source_esolver/snap_solver.cpp b/source/source_esolver/esolver_snap.cpp similarity index 93% rename from source/source_esolver/snap_solver.cpp rename to source/source_esolver/esolver_snap.cpp index 7c2290c9553..e55596b3ebc 100644 --- a/source/source_esolver/snap_solver.cpp +++ b/source/source_esolver/esolver_snap.cpp @@ -1,4 +1,4 @@ -#include "snap_solver.h" +#include "esolver_snap.h" #include "source_base/constants.h" #include "source_base/global_variable.h" @@ -50,7 +50,7 @@ ModuleMD::SNAP::Neighbor make_neighbor(const NeighborAtom& center, + parameters.element_radii[static_cast(neighbor.atom_type)]) * parameters.rcutfac; result.element_index = static_cast(neighbor.atom_type); - if (parameters.inner_flag) + if (parameters.switchinner_flag) { const std::size_t center_type = static_cast(center.atom_type); const std::size_t neighbor_type = static_cast(neighbor.atom_type); @@ -61,10 +61,10 @@ ModuleMD::SNAP::Neighbor make_neighbor(const NeighborAtom& center, } } -ESolver_SNAP::ESolver_SNAP(const std::string& coeff_file, +ESolver_SNAP::ESolver_SNAP(const std::string& coefficient_file, const std::string& parameter_file, std::ofstream& running_log) - : coeff_file_(coeff_file), parameter_file_(parameter_file), running_log_(running_log) + : coefficient_file_(coefficient_file), parameter_file_(parameter_file), running_log_(running_log) { classname = "ESolver_SNAP"; } @@ -72,17 +72,17 @@ ESolver_SNAP::ESolver_SNAP(const std::string& coeff_file, void ESolver_SNAP::initialize(const std::vector& labels) { std::string error; - if (!model_.load(coeff_file_, parameter_file_, labels, error)) + if (!model_.load(coefficient_file_, parameter_file_, labels, error)) { fail(error); } - const std::string coeff_path = full_path(coeff_file_); + const std::string coefficient_path = full_path(coefficient_file_); const std::string parameter_path = full_path(parameter_file_); - running_log_ << " Read SNAP coefficient file: " << coeff_path << std::endl; + running_log_ << " Read SNAP coefficient file: " << coefficient_path << std::endl; running_log_ << " Read SNAP parameter file: " << parameter_path << std::endl; if (GlobalV::MY_RANK == 0) { - std::cout << " Read SNAP coefficient file: " << coeff_path << std::endl; + std::cout << " Read SNAP coefficient file: " << coefficient_path << std::endl; std::cout << " Read SNAP parameter file: " << parameter_path << std::endl; } calculator_.reset(new ModuleMD::SNAP::Calculator(model_)); @@ -141,7 +141,7 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) try i, i); std::vector neighbors; - std::vector neigh_indices; + std::vector neighbor_indices; for (int k = 0; k < list.get_numneigh(i); ++k) { const int neighbor_index = list.get_firstneigh(i)[k]; @@ -151,12 +151,12 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) try fail("MDCell atom type is outside the SNAP element map."); } neighbors.push_back(make_neighbor(center, neighbor, mdcell.lat0(), model_.parameters)); - neigh_indices.push_back(static_cast(neighbor_index)); + neighbor_indices.push_back(static_cast(neighbor_index)); } const std::size_t center_element = static_cast(center.atom_type); - const ModuleMD::SNAP::ForceResult result = calculator_->eval_force(neighbors, center_element); + const ModuleMD::SNAP::ForceResult result = calculator_->compute_with_analytic_force(neighbors, center_element); const std::size_t center_index = static_cast(i); - contribution.add(center_index, neigh_indices, neighbors, result); + contribution.add(center_index, neighbor_indices, neighbors, result); } snap_potential_ = contribution.energy() / ModuleBase::Ry_to_eV; const double virial_scale = 1.0 / (ModuleBase::Ry_to_eV * mdcell.omega()); @@ -218,7 +218,7 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) try atom_indices.push_back(index); } const std::size_t center_element = static_cast(center.atom_type); - const ModuleMD::SNAP::ForceResult result = calculator_->eval_force(neighbors, center_element); + const ModuleMD::SNAP::ForceResult result = calculator_->compute_with_analytic_force(neighbors, center_element); const int center_index = offsets[static_cast(center.atom_type)] + center.atom_index; const std::size_t index = static_cast(center_index); contribution.add(index, atom_indices, neighbors, result); diff --git a/source/source_esolver/snap_solver.h b/source/source_esolver/esolver_snap.h similarity index 88% rename from source/source_esolver/snap_solver.h rename to source/source_esolver/esolver_snap.h index 850fc22b62e..cad1b79af4a 100644 --- a/source/source_esolver/snap_solver.h +++ b/source/source_esolver/esolver_snap.h @@ -2,7 +2,7 @@ #define ESOLVER_SNAP_H #include "esolver.h" -#include "source_md/module_snap/calc.h" +#include "source_md/module_snap/snap_calculator.h" #include #include @@ -15,7 +15,7 @@ namespace ModuleESolver class ESolver_SNAP : public ESolver { public: - ESolver_SNAP(const std::string& coeff_file, + ESolver_SNAP(const std::string& coefficient_file, const std::string& parameter_file, std::ofstream& running_log); @@ -29,7 +29,7 @@ class ESolver_SNAP : public ESolver private: void initialize(const std::vector& labels); - std::string coeff_file_; + std::string coefficient_file_; std::string parameter_file_; std::ofstream& running_log_; ModuleMD::SNAP::ModelData model_; diff --git a/source/source_md/module_snap/CMakeLists.txt b/source/source_md/module_snap/CMakeLists.txt index 3a427947a6a..9eec1beaee4 100644 --- a/source/source_md/module_snap/CMakeLists.txt +++ b/source/source_md/module_snap/CMakeLists.txt @@ -1,13 +1,13 @@ target_sources( md PRIVATE - calc.cpp - desc.cpp - deriv.cpp - model.cpp - cg.cpp + snap_calculator.cpp + snap_descriptor.cpp + snap_derivative.cpp + snap_model.cpp + snap_clebsch_gordan.cpp ) if(BUILD_TESTING) - add_subdirectory(unittests) + add_subdirectory(unittest) endif() diff --git a/source/source_md/module_snap/calc.cpp b/source/source_md/module_snap/snap_calculator.cpp similarity index 79% rename from source/source_md/module_snap/calc.cpp rename to source/source_md/module_snap/snap_calculator.cpp index 1e998527c04..5e33e78094d 100644 --- a/source/source_md/module_snap/calc.cpp +++ b/source/source_md/module_snap/snap_calculator.cpp @@ -1,4 +1,4 @@ -#include "calc.h" +#include "snap_calculator.h" #include @@ -9,18 +9,18 @@ namespace SNAP Calculator::Calculator(const ModelData& model) : model_(model), - desc_eval_(model.parameters), - desc_size_(0) + descriptor_evaluator_(model.parameters), + descriptor_size_(0) { - const std::size_t channels = desc_eval_.channel_count(); - desc_size_ = desc_eval_.bispectrum_size() * channels * channels * channels; + const std::size_t channels = descriptor_evaluator_.channel_count(); + descriptor_size_ = descriptor_evaluator_.bispectrum_size() * channels * channels * channels; if (model_.coefficients.size() != model_.parameters.elements.size()) { throw std::invalid_argument("SNAP coefficient blocks do not match the element list."); } - const std::size_t expected_count = desc_size_ + 1 + const std::size_t expected_count = descriptor_size_ + 1 + (model_.parameters.quadratic_flag - ? desc_size_ * (desc_size_ + 1) / 2 + ? descriptor_size_ * (descriptor_size_ + 1) / 2 : 0); for (std::size_t element = 0; element < model_.coefficients.size(); ++element) { @@ -39,13 +39,13 @@ EnergyResult Calculator::compute(const std::vector& neighbors, const s } EnergyResult result; - result.descriptor = desc_eval_.calc_bispec( - desc_eval_.accumulate_u(neighbors, central_element)); + result.descriptor = descriptor_evaluator_.compute_bispectrum( + descriptor_evaluator_.accumulate_u(neighbors, central_element)); if (model_.parameters.bzero_flag) { const std::vector bzero = - desc_eval_.calc_bispec( - desc_eval_.accumulate_u(std::vector(), central_element)); + descriptor_evaluator_.compute_bispectrum( + descriptor_evaluator_.accumulate_u(std::vector(), central_element)); for (std::size_t index = 0; index < result.descriptor.size(); ++index) { result.descriptor[index] -= bzero[index]; @@ -72,7 +72,7 @@ EnergyResult Calculator::compute(const std::vector& neighbors, const s return result; } -ForceResult Calculator::eval_force(const std::vector& neighbors, +ForceResult Calculator::compute_with_analytic_force(const std::vector& neighbors, const std::size_t central_element) const { if (central_element >= model_.coefficients.size()) @@ -84,24 +84,24 @@ ForceResult Calculator::eval_force(const std::vector& neighbors, result.center_force.assign(3, 0.0); result.neighbor_forces.assign(neighbors.size(), std::vector(3, 0.0)); const std::vector& coefficients = model_.coefficients[central_element]; - const std::vector > u = desc_eval_.accumulate_u(neighbors, central_element); + const std::vector > u = descriptor_evaluator_.accumulate_u(neighbors, central_element); for (std::size_t neighbor_index = 0; neighbor_index < neighbors.size(); ++neighbor_index) { for (int direction = 0; direction < 3; ++direction) { const UWithDerivative u_derivative = - desc_eval_.calc_u_deriv(neighbors[neighbor_index], direction); + descriptor_evaluator_.compute_u_with_derivative(neighbors[neighbor_index], direction); std::vector > du(u.size(), std::complex(0.0, 0.0)); - const std::size_t deriv_offset = model_.parameters.chem_flag + const std::size_t derivative_offset = model_.parameters.chem_flag ? neighbors[neighbor_index].element_index - * desc_eval_.u_size() + * descriptor_evaluator_.u_size() : 0; - const std::vector >& one_neigh_deriv = u_derivative.derivatives; - for (std::size_t index = 0; index < one_neigh_deriv.size(); ++index) + const std::vector >& one_neighbor_derivative = u_derivative.derivatives; + for (std::size_t index = 0; index < one_neighbor_derivative.size(); ++index) { - du[deriv_offset + index] = one_neigh_deriv[index]; + du[derivative_offset + index] = one_neighbor_derivative[index]; } - const std::vector db = desc_eval_.calc_b_deriv(u, du); + const std::vector db = descriptor_evaluator_.compute_bispectrum_derivative(u, du); double derivative = 0.0; for (std::size_t index = 0; index < db.size(); ++index) { @@ -128,7 +128,7 @@ ForceResult Calculator::eval_force(const std::vector& neighbors, return result; } -ForceResult Calculator::eval_force_fd(const std::vector& neighbors, +ForceResult Calculator::compute_with_finite_difference_force(const std::vector& neighbors, const std::size_t central_element, const double displacement) const { @@ -181,18 +181,18 @@ CellAccumulator::CellAccumulator(const std::size_t atom_count) : forces_(atom_co } void CellAccumulator::add(const std::size_t center_index, - const std::vector& neigh_indices, + const std::vector& neighbor_indices, const std::vector& neighbors, const ForceResult& result) { - if (center_index >= forces_.size() || neigh_indices.size() != neighbors.size() + if (center_index >= forces_.size() || neighbor_indices.size() != neighbors.size() || result.neighbor_forces.size() != neighbors.size() || result.center_force.size() != 3) { throw std::invalid_argument("SNAP cell contribution has inconsistent atom or force indices."); } - for (std::size_t index = 0; index < neigh_indices.size(); ++index) + for (std::size_t index = 0; index < neighbor_indices.size(); ++index) { - if (neigh_indices[index] >= forces_.size() || result.neighbor_forces[index].size() != 3) + if (neighbor_indices[index] >= forces_.size() || result.neighbor_forces[index].size() != 3) { throw std::invalid_argument("SNAP neighbor force index is outside the cell."); } @@ -208,7 +208,7 @@ void CellAccumulator::add(const std::size_t center_index, { const Neighbor& neighbor = neighbors[index]; const double displacement[3] = {neighbor.x, neighbor.y, neighbor.z}; - const std::size_t atom = neigh_indices[index]; + const std::size_t atom = neighbor_indices[index]; for (int direction = 0; direction < 3; ++direction) { forces_[atom][static_cast(direction)] += diff --git a/source/source_md/module_snap/calc.h b/source/source_md/module_snap/snap_calculator.h similarity index 73% rename from source/source_md/module_snap/calc.h rename to source/source_md/module_snap/snap_calculator.h index 6e1791f3cbb..3bbc9caead9 100644 --- a/source/source_md/module_snap/calc.h +++ b/source/source_md/module_snap/snap_calculator.h @@ -1,8 +1,8 @@ -#ifndef SNAP_CALC_H -#define SNAP_CALC_H +#ifndef SNAP_CALCULATOR_H +#define SNAP_CALCULATOR_H -#include "desc.h" -#include "model.h" +#include "snap_descriptor.h" +#include "snap_model.h" #include #include @@ -32,22 +32,22 @@ class Calculator EnergyResult compute(const std::vector& neighbors, std::size_t central_element) const; - ForceResult eval_force(const std::vector& neighbors, + ForceResult compute_with_analytic_force(const std::vector& neighbors, std::size_t central_element) const; - ForceResult eval_force_fd(const std::vector& neighbors, + ForceResult compute_with_finite_difference_force(const std::vector& neighbors, std::size_t central_element, double displacement) const; std::size_t descriptor_size() const { - return desc_size_; + return descriptor_size_; } private: ModelData model_; - DescEval desc_eval_; - std::size_t desc_size_; + DescriptorEvaluator descriptor_evaluator_; + std::size_t descriptor_size_; }; class CellAccumulator @@ -56,7 +56,7 @@ class CellAccumulator explicit CellAccumulator(std::size_t atom_count); void add(std::size_t center_index, - const std::vector& neigh_indices, + const std::vector& neighbor_indices, const std::vector& neighbors, const ForceResult& result); @@ -73,4 +73,4 @@ class CellAccumulator } // namespace SNAP } // namespace ModuleMD -#endif // SNAP_CALC_H +#endif // SNAP_CALCULATOR_H diff --git a/source/source_md/module_snap/cg.cpp b/source/source_md/module_snap/snap_clebsch_gordan.cpp similarity index 90% rename from source/source_md/module_snap/cg.cpp rename to source/source_md/module_snap/snap_clebsch_gordan.cpp index bfa3e5eb372..f2d65865662 100644 --- a/source/source_md/module_snap/cg.cpp +++ b/source/source_md/module_snap/snap_clebsch_gordan.cpp @@ -1,4 +1,4 @@ -#include "cg.h" +#include "snap_clebsch_gordan.h" #include @@ -15,7 +15,7 @@ int half_sum(const int left, const int right) } } -CGTable::CGTable(const int twojmax) +ClebschGordanTable::ClebschGordanTable(const int twojmax) { twojmax_ = twojmax < 0 ? 0 : twojmax; for (int j1 = 0; j1 <= twojmax_; ++j1) @@ -40,7 +40,7 @@ CGTable::CGTable(const int twojmax) entry.m2 = m2; entry.j = j; entry.m = m; - entry.value = coeff_raw(j1, m1, j2, m2, j, m); + entry.value = coefficient_uncached(j1, m1, j2, m2, j, m); entries_.push_back(entry); } } @@ -49,7 +49,7 @@ CGTable::CGTable(const int twojmax) } } -double CGTable::factorial(const int value) +double ClebschGordanTable::factorial(const int value) { if (value < 0) { @@ -58,7 +58,7 @@ double CGTable::factorial(const int value) return std::tgamma(static_cast(value) + 1.0); } -bool CGTable::allowed(const int j1, +bool ClebschGordanTable::allowed(const int j1, const int m1, const int j2, const int m2, @@ -80,7 +80,7 @@ bool CGTable::allowed(const int j1, return m == m1 + m2; } -double CGTable::coeff_raw(const int j1, +double ClebschGordanTable::coefficient_uncached(const int j1, const int m1, const int j2, const int m2, @@ -123,7 +123,7 @@ double CGTable::coeff_raw(const int j1, return delta * prefactor * sum; } -const CGTable::Entry* CGTable::find(const int j1, +const ClebschGordanTable::Entry* ClebschGordanTable::find(const int j1, const int m1, const int j2, const int m2, @@ -141,7 +141,7 @@ const CGTable::Entry* CGTable::find(const int j1, return nullptr; } -double CGTable::coefficient(const int j1, +double ClebschGordanTable::coefficient(const int j1, const int m1, const int j2, const int m2, @@ -152,7 +152,7 @@ double CGTable::coefficient(const int j1, return entry == nullptr ? 0.0 : entry->value; } -double CGTable::h_coefficient(const int j1, +double ClebschGordanTable::h_coefficient(const int j1, const int m1, const int mp1, const int j2, diff --git a/source/source_md/module_snap/cg.h b/source/source_md/module_snap/snap_clebsch_gordan.h similarity index 81% rename from source/source_md/module_snap/cg.h rename to source/source_md/module_snap/snap_clebsch_gordan.h index 01cc732e18f..978c255d985 100644 --- a/source/source_md/module_snap/cg.h +++ b/source/source_md/module_snap/snap_clebsch_gordan.h @@ -1,5 +1,5 @@ -#ifndef SNAP_CG_H -#define SNAP_CG_H +#ifndef SNAP_CLEBSCH_GORDAN_H +#define SNAP_CLEBSCH_GORDAN_H #include @@ -14,10 +14,10 @@ namespace SNAP * If the stored index is j, the physical angular momentum is j/2. The same * convention is used for m and m'. */ -class CGTable +class ClebschGordanTable { public: - explicit CGTable(int twojmax); + explicit ClebschGordanTable(int twojmax); double coefficient(int j1, int m1, int j2, int m2, int j, int m) const; @@ -44,7 +44,7 @@ class CGTable }; static bool allowed(int j1, int m1, int j2, int m2, int j, int m); - static double coeff_raw(int j1, int m1, int j2, int m2, int j, int m); + static double coefficient_uncached(int j1, int m1, int j2, int m2, int j, int m); static double factorial(int value); const Entry* find(int j1, int m1, int j2, int m2, int j, int m) const; @@ -55,4 +55,4 @@ class CGTable } // namespace SNAP } // namespace ModuleMD -#endif // SNAP_CG_H +#endif // SNAP_CLEBSCH_GORDAN_H diff --git a/source/source_md/module_snap/deriv.cpp b/source/source_md/module_snap/snap_derivative.cpp similarity index 97% rename from source/source_md/module_snap/deriv.cpp rename to source/source_md/module_snap/snap_derivative.cpp index 61fd87a0b50..cea61b8a31b 100644 --- a/source/source_md/module_snap/deriv.cpp +++ b/source/source_md/module_snap/snap_derivative.cpp @@ -1,4 +1,4 @@ -#include "desc.h" +#include "snap_descriptor.h" #include "source_base/constants.h" @@ -106,7 +106,7 @@ Dual dual_tan(const Dual& value) } } -UWithDerivative DescEval::calc_u_deriv(const Neighbor& neighbor, const int direction) const +UWithDerivative DescriptorEvaluator::compute_u_with_derivative(const Neighbor& neighbor, const int direction) const { if (direction < 0 || direction > 2) { diff --git a/source/source_md/module_snap/desc.cpp b/source/source_md/module_snap/snap_descriptor.cpp similarity index 92% rename from source/source_md/module_snap/desc.cpp rename to source/source_md/module_snap/snap_descriptor.cpp index 43f02919001..a0c33db3b64 100644 --- a/source/source_md/module_snap/desc.cpp +++ b/source/source_md/module_snap/snap_descriptor.cpp @@ -1,4 +1,4 @@ -#include "desc.h" +#include "snap_descriptor.h" #include "source_base/constants.h" @@ -11,7 +11,7 @@ namespace ModuleMD namespace SNAP { -DescEval::DescEval(const ModelParameters& parameters) +DescriptorEvaluator::DescriptorEvaluator(const ModelParameters& parameters) : parameters_(parameters), cg_table_(parameters.twojmax), u_size_(0) { std::string error; @@ -40,14 +40,14 @@ DescEval::DescEval(const ModelParameters& parameters) index.j1 = j1; index.j2 = j2; index.j = j; - bispec_indices_.push_back(index); + bispectrum_indices_.push_back(index); } } } } } -void DescEval::compute_rootpq() +void DescriptorEvaluator::compute_rootpq() { const int dimension = parameters_.twojmax + 1; rootpq_.assign(static_cast(dimension * dimension), 0.0); @@ -60,12 +60,12 @@ void DescEval::compute_rootpq() } } -std::size_t DescEval::u_index(const int j, const int ma, const int mb) const +std::size_t DescriptorEvaluator::u_index(const int j, const int ma, const int mb) const { return u_block_[static_cast(j)] + static_cast(mb * (j + 1) + ma); } -DescEval::SwitchValue DescEval::switching(const double distance, +DescriptorEvaluator::SwitchValue DescriptorEvaluator::switching(const double distance, const Neighbor& neighbor, const double cutoff_radius) const { @@ -84,7 +84,7 @@ DescEval::SwitchValue DescEval::switching(const double distance, result.value = 0.5 * (std::cos(angle) + 1.0); result.derivative = -0.5 * std::sin(angle) * angle_scale; } - if (parameters_.inner_flag) + if (parameters_.switchinner_flag) { const double inner_start = neighbor.sinner - neighbor.dinner; const double inner_end = neighbor.sinner + neighbor.dinner; @@ -98,15 +98,15 @@ DescEval::SwitchValue DescEval::switching(const double distance, const double angle_scale = 0.5 * ModuleBase::PI / neighbor.dinner; const double angle = (distance - inner_start) * angle_scale; const double inner_value = 0.5 * (1.0 - std::cos(angle)); - const double inner_deriv = 0.5 * std::sin(angle) * angle_scale; - result.derivative = result.derivative * inner_value + result.value * inner_deriv; + const double inner_derivative = 0.5 * std::sin(angle) * angle_scale; + result.derivative = result.derivative * inner_value + result.value * inner_derivative; result.value *= inner_value; } } return result; } -std::vector > DescEval::compute_u(const Neighbor& neighbor) const +std::vector > DescriptorEvaluator::compute_u(const Neighbor& neighbor) const { const double rsq = neighbor.x * neighbor.x + neighbor.y * neighbor.y + neighbor.z * neighbor.z; const double distance = std::sqrt(rsq); @@ -162,12 +162,12 @@ std::vector > DescEval::compute_u(const Neighbor& neighbor) return result; } -std::vector > DescEval::accumulate_u(const std::vector& neighbors) const +std::vector > DescriptorEvaluator::accumulate_u(const std::vector& neighbors) const { return accumulate_u(neighbors, 0); } -std::vector > DescEval::accumulate_u(const std::vector& neighbors, +std::vector > DescriptorEvaluator::accumulate_u(const std::vector& neighbors, const std::size_t central_element) const { const std::size_t channels = channel_count(); @@ -217,20 +217,20 @@ std::vector > DescEval::accumulate_u(const std::vector DescEval::calc_bispec(const std::vector >& u) const +std::vector DescriptorEvaluator::compute_bispectrum(const std::vector >& u) const { const std::size_t channels = channel_count(); if (u.size() != channels * u_size_) { throw std::invalid_argument("SNAP u array has an unexpected size."); } - const std::size_t bispectrum_size = bispec_indices_.size(); + const std::size_t bispectrum_size = bispectrum_indices_.size(); std::vector result(channels * channels * channels * bispectrum_size, 0.0); const auto compute_one = [this, &u](const std::size_t first_channel, const std::size_t second_channel, const std::size_t third_channel, - const std::size_t bispec_index) { - const BispectrumIndex& index = bispec_indices_[bispec_index]; + const std::size_t bispectrum_index) { + const BispectrumIndex& index = bispectrum_indices_[bispectrum_index]; const std::size_t first_offset = first_channel * u_size_; const std::size_t second_offset = second_channel * u_size_; const std::size_t third_offset = third_channel * u_size_; @@ -305,7 +305,7 @@ std::vector DescEval::calc_bispec(const std::vector return result; } -std::vector DescEval::calc_b_deriv( +std::vector DescriptorEvaluator::compute_bispectrum_derivative( const std::vector >& u, const std::vector >& du) const { @@ -314,13 +314,13 @@ std::vector DescEval::calc_b_deriv( { throw std::invalid_argument("SNAP u derivative array has an unexpected size."); } - const std::size_t bispectrum_size = bispec_indices_.size(); + const std::size_t bispectrum_size = bispectrum_indices_.size(); std::vector result(channels * channels * channels * bispectrum_size, 0.0); const auto compute_one = [this, &u, &du](const std::size_t first_channel, const std::size_t second_channel, const std::size_t third_channel, - const std::size_t bispec_index) { - const BispectrumIndex& index = bispec_indices_[bispec_index]; + const std::size_t bispectrum_index) { + const BispectrumIndex& index = bispectrum_indices_[bispectrum_index]; const std::size_t first_offset = first_channel * u_size_; const std::size_t second_offset = second_channel * u_size_; const std::size_t third_offset = third_channel * u_size_; diff --git a/source/source_md/module_snap/desc.h b/source/source_md/module_snap/snap_descriptor.h similarity index 72% rename from source/source_md/module_snap/desc.h rename to source/source_md/module_snap/snap_descriptor.h index ec2a601e3aa..a20f495bac4 100644 --- a/source/source_md/module_snap/desc.h +++ b/source/source_md/module_snap/snap_descriptor.h @@ -1,8 +1,8 @@ -#ifndef SNAP_DESC_H -#define SNAP_DESC_H +#ifndef SNAP_DESCRIPTOR_H +#define SNAP_DESCRIPTOR_H -#include "cg.h" -#include "model.h" +#include "snap_clebsch_gordan.h" +#include "snap_model.h" #include #include @@ -30,23 +30,23 @@ struct UWithDerivative std::vector > derivatives; }; -class DescEval +class DescriptorEvaluator { public: - explicit DescEval(const ModelParameters& parameters); + explicit DescriptorEvaluator(const ModelParameters& parameters); std::vector > compute_u(const Neighbor& neighbor) const; - UWithDerivative calc_u_deriv(const Neighbor& neighbor, int direction) const; + UWithDerivative compute_u_with_derivative(const Neighbor& neighbor, int direction) const; std::vector > accumulate_u(const std::vector& neighbors) const; std::vector > accumulate_u(const std::vector& neighbors, std::size_t central_element) const; - std::vector calc_bispec(const std::vector >& u) const; + std::vector compute_bispectrum(const std::vector >& u) const; - std::vector calc_b_deriv(const std::vector >& u, + std::vector compute_bispectrum_derivative(const std::vector >& u, const std::vector >& du) const; std::size_t u_size() const @@ -56,7 +56,7 @@ class DescEval std::size_t bispectrum_size() const { - return bispec_indices_.size(); + return bispectrum_indices_.size(); } std::size_t channel_count() const @@ -82,14 +82,14 @@ class DescEval void compute_rootpq(); ModelParameters parameters_; - CGTable cg_table_; + ClebschGordanTable cg_table_; std::vector rootpq_; std::vector u_block_; - std::vector bispec_indices_; + std::vector bispectrum_indices_; std::size_t u_size_; }; } // namespace SNAP } // namespace ModuleMD -#endif // SNAP_DESC_H +#endif // SNAP_DESCRIPTOR_H diff --git a/source/source_md/module_snap/model.cpp b/source/source_md/module_snap/snap_model.cpp similarity index 83% rename from source/source_md/module_snap/model.cpp rename to source/source_md/module_snap/snap_model.cpp index 04d9c3d9382..6df5673d859 100644 --- a/source/source_md/module_snap/model.cpp +++ b/source/source_md/module_snap/snap_model.cpp @@ -1,4 +1,4 @@ -#include "model.h" +#include "snap_model.h" #include #include #include @@ -26,7 +26,7 @@ bool next_data_line(std::istream& input, std::string& line) } template -bool read_param(std::istringstream& words, T& value, const std::string& keyword, std::string& error) +bool read_parameter_value(std::istringstream& words, T& value, const std::string& keyword, std::string& error) { if (!(words >> value) || words.fail()) { @@ -38,7 +38,7 @@ bool read_param(std::istringstream& words, T& value, const std::string& keyword, bool validate_inner(const ModuleMD::SNAP::ModelParameters& parameters, std::string& error) { - if (!parameters.inner_flag) + if (!parameters.switchinner_flag) { return true; } @@ -75,7 +75,7 @@ bool validate_cutoff(const ModuleMD::SNAP::ModelParameters& parameters, std::str return true; } -bool valid_cutoffs(const ModuleMD::SNAP::ModelParameters& parameters, std::string& error) +bool validate_pair_cutoffs(const ModuleMD::SNAP::ModelParameters& parameters, std::string& error) { for (std::size_t i = 0; i < parameters.element_radii.size(); ++i) { @@ -148,33 +148,33 @@ bool ModelParameters::valid(std::string& error) const return false; } } - if (!valid_cutoffs(*this, error)) + if (!validate_pair_cutoffs(*this, error)) { return false; } return true; } -bool ModelData::load(const std::string& coeff_file, +bool ModelData::load(const std::string& coefficient_file, const std::string& parameter_file, - const std::vector& wanted_elements, + const std::vector& requested_elements, std::string& error) { error.clear(); parameters = ModelParameters(); parameters.rfac0 = 0.99363; coefficients.clear(); - parameters.elements = wanted_elements; + parameters.elements = requested_elements; if (parameters.elements.empty()) { error = "SNAP requires at least one requested element."; return false; } - std::ifstream coeff_stream(coeff_file.c_str()); + std::ifstream coeff_stream(coefficient_file.c_str()); if (!coeff_stream) { - error = "Cannot open SNAP coefficient file: " + coeff_file; + error = "Cannot open SNAP coefficient file: " + coefficient_file; return false; } @@ -186,8 +186,8 @@ bool ModelData::load(const std::string& coeff_file, } std::istringstream header(line); int block_count = 0; - int coeff_count = 0; - if (!(header >> block_count >> coeff_count) || block_count <= 0 || coeff_count <= 0) + int coefficient_count = 0; + if (!(header >> block_count >> coefficient_count) || block_count <= 0 || coefficient_count <= 0) { error = "Invalid SNAP coefficient file header."; return false; @@ -222,8 +222,8 @@ bool ModelData::load(const std::string& coeff_file, break; } } - std::vector values(static_cast(coeff_count), 0.0); - for (int coefficient = 0; coefficient < coeff_count; ++coefficient) + std::vector values(static_cast(coefficient_count), 0.0); + for (int coefficient = 0; coefficient < coefficient_count; ++coefficient) { if (!next_data_line(coeff_stream, line)) { @@ -259,8 +259,8 @@ bool ModelData::load(const std::string& coeff_file, } } - std::ifstream param_stream(parameter_file.c_str()); - if (!param_stream) + std::ifstream parameter_stream(parameter_file.c_str()); + if (!parameter_stream) { error = "Cannot open SNAP parameter file: " + parameter_file; return false; @@ -269,14 +269,14 @@ bool ModelData::load(const std::string& coeff_file, bool has_twojmax = false; bool has_sinner = false; bool has_dinner = false; - while (next_data_line(param_stream, line)) + while (next_data_line(parameter_stream, line)) { std::istringstream words(line); std::string keyword; words >> keyword; if (keyword == "rcutfac") { - if (!read_param(words, parameters.rcutfac, keyword, error)) + if (!read_parameter_value(words, parameters.rcutfac, keyword, error)) { return false; } @@ -284,7 +284,7 @@ bool ModelData::load(const std::string& coeff_file, } else if (keyword == "twojmax") { - if (!read_param(words, parameters.twojmax, keyword, error)) + if (!read_parameter_value(words, parameters.twojmax, keyword, error)) { return false; } @@ -292,14 +292,14 @@ bool ModelData::load(const std::string& coeff_file, } else if (keyword == "rfac0") { - if (!read_param(words, parameters.rfac0, keyword, error)) + if (!read_parameter_value(words, parameters.rfac0, keyword, error)) { return false; } } else if (keyword == "rmin0") { - if (!read_param(words, parameters.rmin, keyword, error)) + if (!read_parameter_value(words, parameters.rmin, keyword, error)) { return false; } @@ -307,7 +307,7 @@ bool ModelData::load(const std::string& coeff_file, else if (keyword == "bnormflag") { int value = 0; - if (!read_param(words, value, keyword, error)) + if (!read_parameter_value(words, value, keyword, error)) { return false; } @@ -316,7 +316,7 @@ bool ModelData::load(const std::string& coeff_file, else if (keyword == "switchflag") { int value = 0; - if (!read_param(words, value, keyword, error)) + if (!read_parameter_value(words, value, keyword, error)) { return false; } @@ -325,7 +325,7 @@ bool ModelData::load(const std::string& coeff_file, else if (keyword == "bzeroflag") { int value = 0; - if (!read_param(words, value, keyword, error)) + if (!read_parameter_value(words, value, keyword, error)) { return false; } @@ -334,7 +334,7 @@ bool ModelData::load(const std::string& coeff_file, else if (keyword == "quadraticflag") { int value = 0; - if (!read_param(words, value, keyword, error)) + if (!read_parameter_value(words, value, keyword, error)) { return false; } @@ -343,7 +343,7 @@ bool ModelData::load(const std::string& coeff_file, else if (keyword == "wselfallflag") { int value = 0; - if (!read_param(words, value, keyword, error)) + if (!read_parameter_value(words, value, keyword, error)) { return false; } @@ -352,7 +352,7 @@ bool ModelData::load(const std::string& coeff_file, else if (keyword == "chemflag") { int value = 0; - if (!read_param(words, value, keyword, error)) + if (!read_parameter_value(words, value, keyword, error)) { return false; } @@ -361,7 +361,7 @@ bool ModelData::load(const std::string& coeff_file, else if (keyword == "switchinnerflag") { int value = 0; - if (!read_param(words, value, keyword, error)) + if (!read_parameter_value(words, value, keyword, error)) { return false; } @@ -370,7 +370,7 @@ bool ModelData::load(const std::string& coeff_file, error = "SNAP switchinnerflag must be 0 or 1."; return false; } - parameters.inner_flag = value == 1; + parameters.switchinner_flag = value == 1; } else if (keyword == "sinner" || keyword == "dinner") { @@ -378,7 +378,7 @@ bool ModelData::load(const std::string& coeff_file, values.resize(parameters.elements.size()); for (std::size_t i = 0; i < values.size(); ++i) { - if (!read_param(words, values[i], keyword, error)) + if (!read_parameter_value(words, values[i], keyword, error)) { return false; } @@ -395,7 +395,7 @@ bool ModelData::load(const std::string& coeff_file, else if (keyword == "chunksize" || keyword == "parallelthresh") { int value = 0; - if (!read_param(words, value, keyword, error)) + if (!read_parameter_value(words, value, keyword, error)) { return false; } @@ -417,12 +417,12 @@ bool ModelData::load(const std::string& coeff_file, return false; } } - if (parameters.inner_flag && (!has_sinner || !has_dinner)) + if (parameters.switchinner_flag && (!has_sinner || !has_dinner)) { error = "SNAP switchinnerflag=1 requires sinner and dinner."; return false; } - if (!parameters.inner_flag && (has_sinner || has_dinner)) + if (!parameters.switchinner_flag && (has_sinner || has_dinner)) { error = "SNAP sinner and dinner require switchinnerflag=1."; return false; @@ -441,7 +441,7 @@ bool ModelData::load(const std::string& coeff_file, return parameters.valid(error); } -std::size_t ModelData::coeff_count() const +std::size_t ModelData::coefficient_count() const { if (coefficients.empty()) { diff --git a/source/source_md/module_snap/model.h b/source/source_md/module_snap/snap_model.h similarity index 83% rename from source/source_md/module_snap/model.h rename to source/source_md/module_snap/snap_model.h index e00b642ff50..806018c19b3 100644 --- a/source/source_md/module_snap/model.h +++ b/source/source_md/module_snap/snap_model.h @@ -22,7 +22,7 @@ struct ModelParameters bool bzero_flag = true; bool quadratic_flag = false; bool wselfall_flag = false; - bool inner_flag = false; + bool switchinner_flag = false; double wself = 1.0; std::vector elements; std::vector element_weights; @@ -38,12 +38,12 @@ struct ModelData ModelParameters parameters; std::vector > coefficients; - bool load(const std::string& coeff_file, + bool load(const std::string& coefficient_file, const std::string& parameter_file, - const std::vector& wanted_elements, + const std::vector& requested_elements, std::string& error); - std::size_t coeff_count() const; + std::size_t coefficient_count() const; }; } // namespace SNAP diff --git a/source/source_md/module_snap/unittest/CMakeLists.txt b/source/source_md/module_snap/unittest/CMakeLists.txt new file mode 100644 index 00000000000..adf73f1ad39 --- /dev/null +++ b/source/source_md/module_snap/unittest/CMakeLists.txt @@ -0,0 +1,21 @@ +AddTest( + TARGET MODULE_MD_SNAP_model + SOURCES test_snap_model.cpp ../snap_model.cpp +) + +AddTest( + TARGET MODULE_MD_SNAP_clebsch_gordan + SOURCES test_snap_clebsch_gordan.cpp ../snap_clebsch_gordan.cpp +) + +AddTest( + TARGET MODULE_MD_SNAP_descriptor + LIBS base device + SOURCES test_snap_descriptor.cpp ../snap_descriptor.cpp ../snap_derivative.cpp ../snap_model.cpp ../snap_clebsch_gordan.cpp +) + +AddTest( + TARGET MODULE_MD_SNAP_calculator + LIBS base device + SOURCES test_snap_calculator.cpp ../snap_calculator.cpp ../snap_descriptor.cpp ../snap_derivative.cpp ../snap_model.cpp ../snap_clebsch_gordan.cpp +) diff --git a/source/source_md/module_snap/unittests/test_calc.cpp b/source/source_md/module_snap/unittest/test_snap_calculator.cpp similarity index 73% rename from source/source_md/module_snap/unittests/test_calc.cpp rename to source/source_md/module_snap/unittest/test_snap_calculator.cpp index a4e5f225c05..33ef835cd02 100644 --- a/source/source_md/module_snap/unittests/test_calc.cpp +++ b/source/source_md/module_snap/unittest/test_snap_calculator.cpp @@ -1,4 +1,4 @@ -#include "../calc.h" +#include "../snap_calculator.h" #include @@ -23,7 +23,7 @@ ModuleMD::SNAP::ModelData make_model() return model; } -ModuleMD::SNAP::ModelData multi_model() +ModuleMD::SNAP::ModelData make_multi_element_model() { ModuleMD::SNAP::ModelData model; model.parameters.rcut = 4.5; @@ -43,7 +43,7 @@ ModuleMD::SNAP::ModelData multi_model() return model; } -ModuleMD::SNAP::ModelData chem_model() +ModuleMD::SNAP::ModelData make_chemical_model() { ModuleMD::SNAP::ModelData model; model.parameters.rcut = 4.5; @@ -67,7 +67,7 @@ ModuleMD::SNAP::ModelData chem_model() return model; } -ModuleMD::SNAP::ModelData quad_model() +ModuleMD::SNAP::ModelData make_angular_quadratic_model() { ModuleMD::SNAP::ModelData model = make_model(); model.parameters.twojmax = 2; @@ -86,7 +86,7 @@ struct SmallCellResult std::array, 3> forces = {}; }; -SmallCellResult eval_cell(const ModuleMD::SNAP::Calculator& calculator, +SmallCellResult evaluate_small_cell(const ModuleMD::SNAP::Calculator& calculator, const std::array, 3>& positions) { SmallCellResult total; @@ -94,7 +94,7 @@ SmallCellResult eval_cell(const ModuleMD::SNAP::Calculator& calculator, for (std::size_t center = 0; center < positions.size(); ++center) { std::vector neighbors; - std::vector neigh_indices; + std::vector neighbor_indices; for (std::size_t atom = 0; atom < positions.size(); ++atom) { if (atom == center) @@ -107,10 +107,10 @@ SmallCellResult eval_cell(const ModuleMD::SNAP::Calculator& calculator, neighbor.z = positions[atom][2] - positions[center][2]; neighbor.cutoff_radius = 4.5; neighbors.push_back(neighbor); - neigh_indices.push_back(atom); + neighbor_indices.push_back(atom); } - const ModuleMD::SNAP::ForceResult result = calculator.eval_force(neighbors, 0); - accumulator.add(center, neigh_indices, neighbors, result); + const ModuleMD::SNAP::ForceResult result = calculator.compute_with_analytic_force(neighbors, 0); + accumulator.add(center, neighbor_indices, neighbors, result); } total.energy = accumulator.energy(); total.virial_xx = accumulator.virial()[0]; @@ -121,7 +121,7 @@ SmallCellResult eval_cell(const ModuleMD::SNAP::Calculator& calculator, return total; } -TEST(SnapCalculator, LinearEnergy) +TEST(SnapCalculator, ComputesLinearAtomicEnergy) { const ModuleMD::SNAP::Calculator calculator(make_model()); ModuleMD::SNAP::Neighbor neighbor; @@ -134,9 +134,9 @@ TEST(SnapCalculator, LinearEnergy) EXPECT_DOUBLE_EQ(result.energy, 2.0 + 3.0 * result.descriptor[0]); } -TEST(SnapCalculator, MultiCenter) +TEST(SnapCalculator, SupportsMultipleCentralElements) { - const ModuleMD::SNAP::Calculator calculator(multi_model()); + const ModuleMD::SNAP::Calculator calculator(make_multi_element_model()); const std::vector neighbors; const ModuleMD::SNAP::EnergyResult silicon = calculator.compute(neighbors, 0); const ModuleMD::SNAP::EnergyResult carbon = calculator.compute(neighbors, 1); @@ -146,9 +146,9 @@ TEST(SnapCalculator, MultiCenter) EXPECT_NE(silicon.energy, carbon.energy); } -TEST(SnapCalculator, ChemChannel) +TEST(SnapCalculator, SupportsChemicalChannels) { - const ModuleMD::SNAP::Calculator calculator(chem_model()); + const ModuleMD::SNAP::Calculator calculator(make_chemical_model()); ModuleMD::SNAP::Neighbor silicon; silicon.x = 1.0; silicon.cutoff_radius = 4.5; @@ -158,42 +158,42 @@ TEST(SnapCalculator, ChemChannel) carbon.element_index = 1; const std::vector neighbors = {silicon, carbon}; - const ModuleMD::SNAP::ForceResult analytic = calculator.eval_force(neighbors, 0); - const ModuleMD::SNAP::ForceResult finite_diff - = calculator.eval_force_fd(neighbors, 0, 1.0e-6); + const ModuleMD::SNAP::ForceResult analytic = calculator.compute_with_analytic_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult finite_difference + = calculator.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); EXPECT_EQ(analytic.energy.descriptor.size(), static_cast(8)); - EXPECT_NEAR(analytic.energy.energy, finite_diff.energy.energy, 1.0e-12); + EXPECT_NEAR(analytic.energy.energy, finite_difference.energy.energy, 1.0e-12); for (int direction = 0; direction < 3; ++direction) { EXPECT_NEAR(analytic.center_force[static_cast(direction)], - finite_diff.center_force[static_cast(direction)], + finite_difference.center_force[static_cast(direction)], 1.0e-5); EXPECT_NEAR(analytic.neighbor_forces[0][static_cast(direction)], - finite_diff.neighbor_forces[0][static_cast(direction)], + finite_difference.neighbor_forces[0][static_cast(direction)], 1.0e-5); } } -TEST(SnapCalculator, BadCoeffCount) +TEST(SnapCalculator, RejectsMismatchedCoefficientCount) { ModuleMD::SNAP::ModelData model = make_model(); model.coefficients[0].push_back(4.0); EXPECT_THROW(ModuleMD::SNAP::Calculator calculator(model), std::invalid_argument); } -TEST(SnapCalculator, BadCenter) +TEST(SnapCalculator, RejectsInvalidCentralElement) { const ModuleMD::SNAP::Calculator calculator(make_model()); EXPECT_THROW(calculator.compute(std::vector(), 1), std::out_of_range); } -TEST(SnapCalculator, PairBalance) +TEST(SnapCalculator, FiniteDifferenceForcesConservePairContribution) { const ModuleMD::SNAP::Calculator calculator(make_model()); ModuleMD::SNAP::Neighbor neighbor; neighbor.x = 1.0; - const ModuleMD::SNAP::ForceResult result = calculator.eval_force_fd( + const ModuleMD::SNAP::ForceResult result = calculator.compute_with_finite_difference_force( std::vector(1, neighbor), 0, 1.0e-5); for (int direction = 0; direction < 3; ++direction) @@ -204,7 +204,7 @@ TEST(SnapCalculator, PairBalance) } } -TEST(SnapCalculator, ForceFinite) +TEST(SnapCalculator, AnalyticForceMatchesFiniteDifference) { const ModuleMD::SNAP::Calculator calculator(make_model()); ModuleMD::SNAP::Neighbor neighbor; @@ -212,8 +212,8 @@ TEST(SnapCalculator, ForceFinite) neighbor.y = 0.4; neighbor.z = -0.2; const std::vector neighbors(1, neighbor); - const ModuleMD::SNAP::ForceResult analytic = calculator.eval_force(neighbors, 0); - const ModuleMD::SNAP::ForceResult finite = calculator.eval_force_fd(neighbors, 0, 1.0e-6); + const ModuleMD::SNAP::ForceResult analytic = calculator.compute_with_analytic_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult finite = calculator.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); for (int direction = 0; direction < 3; ++direction) { EXPECT_NEAR(analytic.neighbor_forces[0][static_cast(direction)], @@ -222,11 +222,11 @@ TEST(SnapCalculator, ForceFinite) } } -TEST(SnapCalculator, InnerFinite) +TEST(SnapCalculator, InnerSwitchMatchesFiniteDifference) { ModuleMD::SNAP::ModelData model = make_model(); model.parameters.twojmax = 2; - model.parameters.inner_flag = true; + model.parameters.switchinner_flag = true; model.parameters.sinner.push_back(1.5); model.parameters.dinner.push_back(0.4); model.coefficients[0] = {0.2, 0.3, -0.1, 0.5, 0.2, -0.4}; @@ -242,8 +242,8 @@ TEST(SnapCalculator, InnerFinite) second.y = 1.7; second.z = -0.2; const std::vector neighbors = {first, second}; - const ModuleMD::SNAP::ForceResult analytic = calculator.eval_force(neighbors, 0); - const ModuleMD::SNAP::ForceResult finite = calculator.eval_force_fd(neighbors, 0, 1.0e-6); + const ModuleMD::SNAP::ForceResult analytic = calculator.compute_with_analytic_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult finite = calculator.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); for (std::size_t i = 0; i < neighbors.size(); ++i) { for (int direction = 0; direction < 3; ++direction) @@ -258,23 +258,23 @@ TEST(SnapCalculator, InnerFinite) model.coefficients[0][6] = 0.25; model.coefficients[0][10] = -0.15; const ModuleMD::SNAP::Calculator quadratic(model); - const ModuleMD::SNAP::ForceResult quad_analytic = quadratic.eval_force(neighbors, 0); - const ModuleMD::SNAP::ForceResult quad_finite = quadratic.eval_force_fd(neighbors, 0, 1.0e-6); + const ModuleMD::SNAP::ForceResult quadratic_analytic = quadratic.compute_with_analytic_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult quadratic_finite = quadratic.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); for (std::size_t i = 0; i < neighbors.size(); ++i) { for (int direction = 0; direction < 3; ++direction) { - EXPECT_NEAR(quad_analytic.neighbor_forces[i][static_cast(direction)], - quad_finite.neighbor_forces[i][static_cast(direction)], 1.0e-5); + EXPECT_NEAR(quadratic_analytic.neighbor_forces[i][static_cast(direction)], + quadratic_finite.neighbor_forces[i][static_cast(direction)], 1.0e-5); } } } -TEST(SnapCalculator, InnerSkip) +TEST(SnapCalculator, InnerSwitchSkipsSingularRadius) { ModuleMD::SNAP::ModelData model = make_model(); model.parameters.rmin = 0.5; - model.parameters.inner_flag = true; + model.parameters.switchinner_flag = true; model.parameters.sinner.push_back(1.5); model.parameters.dinner.push_back(0.4); const ModuleMD::SNAP::Calculator calculator(model); @@ -283,11 +283,11 @@ TEST(SnapCalculator, InnerSkip) neighbor.sinner = 1.5; neighbor.dinner = 0.4; const std::vector neighbors(1, neighbor); - EXPECT_NO_THROW(calculator.eval_force(neighbors, 0)); - model.parameters.inner_flag = false; + EXPECT_NO_THROW(calculator.compute_with_analytic_force(neighbors, 0)); + model.parameters.switchinner_flag = false; const ModuleMD::SNAP::Calculator bare(model); EXPECT_THROW(bare.compute(neighbors, 0), std::domain_error); - EXPECT_THROW(bare.eval_force(neighbors, 0), std::domain_error); + EXPECT_THROW(bare.compute_with_analytic_force(neighbors, 0), std::domain_error); model.parameters.twojmax = 2; model.coefficients[0] = {0.2, 0.3, -0.1, 0.5, 0.2, -0.4}; @@ -295,8 +295,8 @@ TEST(SnapCalculator, InnerSkip) neighbor.x = 0.55; neighbor.y = 0.12; const std::vector near_neighbors(1, neighbor); - const ModuleMD::SNAP::ForceResult near_analytic = angular.eval_force(near_neighbors, 0); - const ModuleMD::SNAP::ForceResult near_finite = angular.eval_force_fd(near_neighbors, 0, 1.0e-6); + const ModuleMD::SNAP::ForceResult near_analytic = angular.compute_with_analytic_force(near_neighbors, 0); + const ModuleMD::SNAP::ForceResult near_finite = angular.compute_with_finite_difference_force(near_neighbors, 0, 1.0e-6); EXPECT_TRUE(std::isfinite(near_analytic.energy.energy)); for (int direction = 0; direction < 3; ++direction) { @@ -306,13 +306,13 @@ TEST(SnapCalculator, InnerSkip) } } -TEST(SnapCalculator, QuadStrain) +TEST(SnapCalculator, AngularQuadraticForcesMatchLammpsAndStrain) { - const ModuleMD::SNAP::Calculator calculator(quad_model()); + const ModuleMD::SNAP::Calculator calculator(make_angular_quadratic_model()); const std::array, 3> positions = {{{0.0, 0.0, 0.0}, {1.058354, 0.0, 0.0}, {0.2645885, 1.3229425, 0.0}}}; - const SmallCellResult result = eval_cell(calculator, positions); + const SmallCellResult result = evaluate_small_cell(calculator, positions); const double lammps_forces[3][2] = {{67.2928038408958, 57.5476436778783}, {-92.1399449575303, 60.5944497536836}, {24.8471411166345, -118.142093431562}}; @@ -334,10 +334,10 @@ TEST(SnapCalculator, QuadStrain) expanded[atom][0] *= 1.0 + strain; contracted[atom][0] *= 1.0 - strain; } - const double expanded_energy = eval_cell(calculator, expanded).energy; - const double strain_energy = eval_cell(calculator, contracted).energy; - const double strain_deriv = (expanded_energy - strain_energy) / (2.0 * strain); - EXPECT_NEAR(result.virial_xx, -strain_deriv, 1.0e-3); + const double expanded_energy = evaluate_small_cell(calculator, expanded).energy; + const double contracted_energy = evaluate_small_cell(calculator, contracted).energy; + const double strain_derivative = (expanded_energy - contracted_energy) / (2.0 * strain); + EXPECT_NEAR(result.virial_xx, -strain_derivative, 1.0e-3); } } // namespace diff --git a/source/source_md/module_snap/unittests/test_cg.cpp b/source/source_md/module_snap/unittest/test_snap_clebsch_gordan.cpp similarity index 60% rename from source/source_md/module_snap/unittests/test_cg.cpp rename to source/source_md/module_snap/unittest/test_snap_clebsch_gordan.cpp index 525650cb3e6..0639ccabfa3 100644 --- a/source/source_md/module_snap/unittests/test_cg.cpp +++ b/source/source_md/module_snap/unittest/test_snap_clebsch_gordan.cpp @@ -1,4 +1,4 @@ -#include "../cg.h" +#include "../snap_clebsch_gordan.h" #include @@ -7,23 +7,23 @@ namespace { -TEST(SnapCG, HighWeight) +TEST(SnapClebschGordan, HighestWeightCoefficientIsOne) { - const ModuleMD::SNAP::CGTable table(2); + const ModuleMD::SNAP::ClebschGordanTable table(2); EXPECT_NEAR(table.coefficient(1, 1, 1, 1, 2, 2), 1.0, 1.0e-14); } -TEST(SnapCG, SingletSigns) +TEST(SnapClebschGordan, SingletHasExpectedSigns) { - const ModuleMD::SNAP::CGTable table(2); + const ModuleMD::SNAP::ClebschGordanTable table(2); const double value = 1.0 / std::sqrt(2.0); EXPECT_NEAR(table.coefficient(1, 1, 1, -1, 0, 0), value, 1.0e-14); EXPECT_NEAR(table.coefficient(1, -1, 1, 1, 0, 0), -value, 1.0e-14); } -TEST(SnapCG, SelectZero) +TEST(SnapClebschGordan, SelectionRulesReturnZero) { - const ModuleMD::SNAP::CGTable table(2); + const ModuleMD::SNAP::ClebschGordanTable table(2); EXPECT_DOUBLE_EQ(table.coefficient(1, 1, 1, 1, 0, 0), 0.0); EXPECT_DOUBLE_EQ(table.coefficient(1, 1, 1, -1, 2, 1), 0.0); EXPECT_DOUBLE_EQ(table.h_coefficient(1, 1, 1, 1, -1, -1, 0, 0, 0), 0.5); diff --git a/source/source_md/module_snap/unittests/test_desc.cpp b/source/source_md/module_snap/unittest/test_snap_descriptor.cpp similarity index 76% rename from source/source_md/module_snap/unittests/test_desc.cpp rename to source/source_md/module_snap/unittest/test_snap_descriptor.cpp index c4e206745ed..0514dd4f6ae 100644 --- a/source/source_md/module_snap/unittests/test_desc.cpp +++ b/source/source_md/module_snap/unittest/test_snap_descriptor.cpp @@ -1,4 +1,4 @@ -#include "../desc.h" +#include "../snap_descriptor.h" #include @@ -22,16 +22,16 @@ ModuleMD::SNAP::ModelParameters make_parameters() return parameters; } -TEST(SnapDescriptor, ArraySizes) +TEST(SnapDescriptor, AllocatesExpectedArraySizes) { - const ModuleMD::SNAP::DescEval evaluator(make_parameters()); + const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); EXPECT_EQ(evaluator.u_size(), static_cast(1 * 1 + 2 * 2 + 3 * 3)); EXPECT_EQ(evaluator.bispectrum_size(), static_cast(5)); } -TEST(SnapDescriptor, SelfDiagonal) +TEST(SnapDescriptor, SelfContributionIsDiagonal) { - const ModuleMD::SNAP::DescEval evaluator(make_parameters()); + const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); const std::vector neighbors; const std::vector > u = evaluator.accumulate_u(neighbors); @@ -43,9 +43,9 @@ TEST(SnapDescriptor, SelfDiagonal) EXPECT_DOUBLE_EQ(u[13].imag(), 0.0); } -TEST(SnapDescriptor, OutsideCutoff) +TEST(SnapDescriptor, OutsideCutoffDoesNotChangeEnvironment) { - const ModuleMD::SNAP::DescEval evaluator(make_parameters()); + const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); ModuleMD::SNAP::Neighbor neighbor; neighbor.x = 5.0; const std::vector neighbors(1, neighbor); @@ -60,15 +60,15 @@ TEST(SnapDescriptor, OutsideCutoff) } } -TEST(SnapDescriptor, FiniteBispec) +TEST(SnapDescriptor, BispectrumIsFinite) { - const ModuleMD::SNAP::DescEval evaluator(make_parameters()); + const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); ModuleMD::SNAP::Neighbor neighbor; neighbor.x = 1.2; neighbor.y = 0.4; neighbor.z = -0.8; const std::vector > u = evaluator.accumulate_u(std::vector(1, neighbor)); - const std::vector bispectrum = evaluator.calc_bispec(u); + const std::vector bispectrum = evaluator.compute_bispectrum(u); for (std::size_t i = 0; i < bispectrum.size(); ++i) { @@ -76,9 +76,9 @@ TEST(SnapDescriptor, FiniteBispec) } } -TEST(SnapDescriptor, LammpsValue) +TEST(SnapDescriptor, MatchesLammpsSingleElementReference) { - const ModuleMD::SNAP::DescEval evaluator(make_parameters()); + const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); const double positions[3][3] = {{1.0, 1.0, 1.0}, {2.0, 1.0, 1.0}, {1.0, 3.0, 1.0}}; std::vector neighbors; for (int atom = 1; atom < 3; ++atom) @@ -90,7 +90,7 @@ TEST(SnapDescriptor, LammpsValue) neighbor.cutoff_radius = 4.0; neighbors.push_back(neighbor); } - const std::vector bispectrum = evaluator.calc_bispec(evaluator.accumulate_u(neighbors)); + const std::vector bispectrum = evaluator.compute_bispectrum(evaluator.accumulate_u(neighbors)); const double reference[5] = { 13.0368348609, 15.0992648922, 11.7631725456, 13.7069739819, 6.07477849248}; ASSERT_EQ(bispectrum.size(), static_cast(5)); diff --git a/source/source_md/module_snap/unittests/test_model.cpp b/source/source_md/module_snap/unittest/test_snap_model.cpp similarity index 70% rename from source/source_md/module_snap/unittests/test_model.cpp rename to source/source_md/module_snap/unittest/test_snap_model.cpp index 81cff30940f..691c56b550e 100644 --- a/source/source_md/module_snap/unittests/test_model.cpp +++ b/source/source_md/module_snap/unittest/test_snap_model.cpp @@ -1,4 +1,4 @@ -#include "../model.h" +#include "../snap_model.h" #include @@ -8,7 +8,7 @@ namespace { -TEST(SnapModel, ValidParams) +TEST(SnapModel, AcceptsCompleteParameters) { ModuleMD::SNAP::ModelParameters parameters; parameters.rcut = 4.5; @@ -25,7 +25,7 @@ TEST(SnapModel, ValidParams) EXPECT_TRUE(error.empty()); } -TEST(SnapModel, BadElements) +TEST(SnapModel, RejectsInconsistentElementData) { ModuleMD::SNAP::ModelParameters parameters; parameters.rcut = 4.5; @@ -40,7 +40,7 @@ TEST(SnapModel, BadElements) EXPECT_FALSE(error.empty()); } -TEST(SnapModel, BadRadial) +TEST(SnapModel, RejectsInvalidRadialRange) { ModuleMD::SNAP::ModelParameters parameters; parameters.rcut = 3.0; @@ -56,7 +56,7 @@ TEST(SnapModel, BadRadial) EXPECT_FALSE(error.empty()); } -TEST(SnapModel, BadPairCutoff) +TEST(SnapModel, RejectsRminOutsideSmallPairCutoff) { ModuleMD::SNAP::ModelParameters parameters; parameters.rcut = 4.0; @@ -71,12 +71,12 @@ TEST(SnapModel, BadPairCutoff) EXPECT_NE(error.find("Small-Small"), std::string::npos); } -TEST(SnapModel, LoadLammps) +TEST(SnapModel, LoadsLammpsStyleCoefficientAndParameterFiles) { - const std::string coeff_file = testing::TempDir() + "snap_coeff_test.txt"; + const std::string coefficient_file = testing::TempDir() + "snap_coeff_test.txt"; const std::string parameter_file = testing::TempDir() + "snap_param_test.txt"; { - std::ofstream output(coeff_file.c_str()); + std::ofstream output(coefficient_file.c_str()); output << "1 3\n"; output << "Si 2.25 1.0\n"; output << "-0.5\n1.25\n2.5\n"; @@ -93,24 +93,24 @@ TEST(SnapModel, LoadLammps) ModuleMD::SNAP::ModelData model; std::string error; - EXPECT_TRUE(model.load(coeff_file, parameter_file, std::vector(1, "Si"), error)); + EXPECT_TRUE(model.load(coefficient_file, parameter_file, std::vector(1, "Si"), error)); EXPECT_TRUE(error.empty()); - ASSERT_EQ(model.coeff_count(), static_cast(3)); + ASSERT_EQ(model.coefficient_count(), static_cast(3)); EXPECT_DOUBLE_EQ(model.parameters.element_weights[0], 1.0); EXPECT_DOUBLE_EQ(model.parameters.element_radii[0], 2.25); EXPECT_DOUBLE_EQ(model.parameters.rcut, 5.4); EXPECT_DOUBLE_EQ(model.coefficients[0][1], 1.25); - std::remove(coeff_file.c_str()); + std::remove(coefficient_file.c_str()); std::remove(parameter_file.c_str()); } -TEST(SnapModel, MultiBlocks) +TEST(SnapModel, LoadsMultipleElementBlocks) { - const std::string coeff_file = testing::TempDir() + "coeff_multi.txt"; - const std::string parameter_file = testing::TempDir() + "param_multi.txt"; + const std::string coefficient_file = testing::TempDir() + "snap_coeff_multi_test.txt"; + const std::string parameter_file = testing::TempDir() + "snap_param_multi_test.txt"; { - std::ofstream output(coeff_file.c_str()); + std::ofstream output(coefficient_file.c_str()); output << "2 2\n"; output << "Si 2.25 1.0\n"; output << "-0.5\n1.25\n"; @@ -129,23 +129,23 @@ TEST(SnapModel, MultiBlocks) ModuleMD::SNAP::ModelData model; std::string error; const std::vector elements = {"Si", "C"}; - EXPECT_TRUE(model.load(coeff_file, parameter_file, elements, error)); + EXPECT_TRUE(model.load(coefficient_file, parameter_file, elements, error)); EXPECT_TRUE(error.empty()); ASSERT_EQ(model.coefficients.size(), static_cast(2)); EXPECT_DOUBLE_EQ(model.parameters.element_weights[1], 0.8); EXPECT_DOUBLE_EQ(model.parameters.element_radii[1], 1.7); EXPECT_DOUBLE_EQ(model.coefficients[1][1], 2.5); - std::remove(coeff_file.c_str()); + std::remove(coefficient_file.c_str()); std::remove(parameter_file.c_str()); } -TEST(SnapModel, ChemBlocks) +TEST(SnapModel, LoadsChemicalCoefficientBlocks) { - const std::string coeff_file = testing::TempDir() + "coeff_chem.txt"; - const std::string parameter_file = testing::TempDir() + "param_chem.txt"; + const std::string coefficient_file = testing::TempDir() + "snap_coeff_chemical_test.txt"; + const std::string parameter_file = testing::TempDir() + "snap_param_chemical_test.txt"; { - std::ofstream output(coeff_file.c_str()); + std::ofstream output(coefficient_file.c_str()); output << "2 9\n"; output << "Si 2.25 1.0\n"; for (int i = 0; i < 9; ++i) @@ -172,31 +172,31 @@ TEST(SnapModel, ChemBlocks) ModuleMD::SNAP::ModelData model; std::string error; const std::vector elements = {"Si", "C"}; - EXPECT_TRUE(model.load(coeff_file, parameter_file, elements, error)); + EXPECT_TRUE(model.load(coefficient_file, parameter_file, elements, error)); EXPECT_TRUE(error.empty()); ASSERT_EQ(model.coefficients.size(), static_cast(2)); EXPECT_TRUE(model.parameters.chem_flag); EXPECT_EQ(model.coefficients[0].size(), static_cast(9)); EXPECT_DOUBLE_EQ(model.coefficients[1][1], 2.0); - const std::vector rev_elements = {"C", "Si"}; + const std::vector reversed_elements = {"C", "Si"}; ModuleMD::SNAP::ModelData reversed; - ASSERT_TRUE(reversed.load(coeff_file, parameter_file, rev_elements, error)) << error; + ASSERT_TRUE(reversed.load(coefficient_file, parameter_file, reversed_elements, error)) << error; EXPECT_EQ(reversed.parameters.elements[0], "C"); EXPECT_EQ(reversed.parameters.elements[1], "Si"); EXPECT_DOUBLE_EQ(reversed.coefficients[0][1], 2.0); EXPECT_DOUBLE_EQ(reversed.coefficients[1][1], 1.0); - std::remove(coeff_file.c_str()); + std::remove(coefficient_file.c_str()); std::remove(parameter_file.c_str()); } -TEST(SnapModel, InnerOptions) +TEST(SnapModel, ReadsInnerSwitchAndRejectsUnknownParameter) { - const std::string coeff_file = testing::TempDir() + "inner_coeff.txt"; - const std::string parameter_file = testing::TempDir() + "inner_param.txt"; + const std::string coefficient_file = testing::TempDir() + "snap_inner_coeff.txt"; + const std::string parameter_file = testing::TempDir() + "snap_inner_param.txt"; { - std::ofstream output(coeff_file.c_str()); + std::ofstream output(coefficient_file.c_str()); output << "1 2\nSi 2.0 1.0\n0.0\n1.0\n"; } { @@ -207,30 +207,30 @@ TEST(SnapModel, InnerOptions) ModuleMD::SNAP::ModelData model; std::string error; const std::vector elements(1, "Si"); - ASSERT_TRUE(model.load(coeff_file, parameter_file, elements, error)) << error; - EXPECT_TRUE(model.parameters.inner_flag); + ASSERT_TRUE(model.load(coefficient_file, parameter_file, elements, error)) << error; + EXPECT_TRUE(model.parameters.switchinner_flag); ASSERT_EQ(model.parameters.sinner.size(), static_cast(1)); EXPECT_DOUBLE_EQ(model.parameters.sinner[0], 1.5); { std::ofstream output(parameter_file.c_str(), std::ios::app); - output << "bad_option 1\n"; + output << "unsupported_option 1\n"; } - EXPECT_FALSE(model.load(coeff_file, parameter_file, elements, error)); - EXPECT_NE(error.find("bad_option"), std::string::npos); + EXPECT_FALSE(model.load(coefficient_file, parameter_file, elements, error)); + EXPECT_NE(error.find("unsupported_option"), std::string::npos); { std::ofstream output(parameter_file.c_str()); output << "rcutfac 1.0\ntwojmax 0\nswitchinnerflag 1\nsinner 1.5\n"; } error.clear(); - EXPECT_FALSE(model.load(coeff_file, parameter_file, elements, error)); + EXPECT_FALSE(model.load(coefficient_file, parameter_file, elements, error)); EXPECT_NE(error.find("requires sinner and dinner"), std::string::npos); { std::ofstream output(parameter_file.c_str()); output << "rcutfac 1.0\ntwojmax 0\nswitchinnerflag 0\n"; } error.clear(); - EXPECT_TRUE(model.load(coeff_file, parameter_file, elements, error)) << error; - std::remove(coeff_file.c_str()); + EXPECT_TRUE(model.load(coefficient_file, parameter_file, elements, error)) << error; + std::remove(coefficient_file.c_str()); std::remove(parameter_file.c_str()); } diff --git a/source/source_md/module_snap/unittests/CMakeLists.txt b/source/source_md/module_snap/unittests/CMakeLists.txt deleted file mode 100644 index c323e0393f6..00000000000 --- a/source/source_md/module_snap/unittests/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -AddTest( - TARGET MODULE_MD_SNAP_model - SOURCES test_model.cpp ../model.cpp -) - -AddTest( - TARGET MODULE_MD_SNAP_clebsch_gordan - SOURCES test_cg.cpp ../cg.cpp -) - -AddTest( - TARGET MODULE_MD_SNAP_descriptor - LIBS base device - SOURCES test_desc.cpp ../desc.cpp ../deriv.cpp ../model.cpp ../cg.cpp -) - -AddTest( - TARGET MODULE_MD_SNAP_calculator - LIBS base device - SOURCES test_calc.cpp ../calc.cpp ../desc.cpp ../deriv.cpp ../model.cpp ../cg.cpp -) From 9e3a45247d2ad700cbd5ab4f583081d75c6ebc3e Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 13:42:00 +0800 Subject: [PATCH 24/33] test: use numbered SNAP model filenames --- tests/04_FF/102_SNAP_base/INPUT | 4 ++-- tests/04_FF/102_SNAP_base/README | 4 ++-- tests/04_FF/103_SNAP_pbc/INPUT | 4 ++-- tests/04_FF/103_SNAP_pbc/README | 4 ++-- tests/04_FF/104_SNAP_inner/INPUT | 4 ++-- tests/04_FF/104_SNAP_inner/README | 4 ++-- tests/04_FF/105_SNAP_quad/INPUT | 4 ++-- tests/04_FF/105_SNAP_quad/README | 4 ++-- tests/04_FF/106_SNAP_scf/INPUT | 4 ++-- tests/04_FF/106_SNAP_scf/README | 4 ++-- .../SIMULATION_MODELS/{snap_102_base.coeff => snap_102.coeff} | 0 .../SIMULATION_MODELS/{snap_102_base.param => snap_102.param} | 0 .../SIMULATION_MODELS/{snap_103_pbc.coeff => snap_103.coeff} | 0 .../SIMULATION_MODELS/{snap_103_pbc.param => snap_103.param} | 0 .../{snap_104_inner.coeff => snap_104.coeff} | 0 .../{snap_104_inner.param => snap_104.param} | 0 .../SIMULATION_MODELS/{snap_105_quad.coeff => snap_105.coeff} | 0 .../SIMULATION_MODELS/{snap_105_quad.param => snap_105.param} | 0 .../SIMULATION_MODELS/{snap_106_scf.coeff => snap_106.coeff} | 0 .../SIMULATION_MODELS/{snap_106_scf.param => snap_106.param} | 0 20 files changed, 20 insertions(+), 20 deletions(-) rename tests/SIMULATION_MODELS/{snap_102_base.coeff => snap_102.coeff} (100%) rename tests/SIMULATION_MODELS/{snap_102_base.param => snap_102.param} (100%) rename tests/SIMULATION_MODELS/{snap_103_pbc.coeff => snap_103.coeff} (100%) rename tests/SIMULATION_MODELS/{snap_103_pbc.param => snap_103.param} (100%) rename tests/SIMULATION_MODELS/{snap_104_inner.coeff => snap_104.coeff} (100%) rename tests/SIMULATION_MODELS/{snap_104_inner.param => snap_104.param} (100%) rename tests/SIMULATION_MODELS/{snap_105_quad.coeff => snap_105.coeff} (100%) rename tests/SIMULATION_MODELS/{snap_105_quad.param => snap_105.param} (100%) rename tests/SIMULATION_MODELS/{snap_106_scf.coeff => snap_106.coeff} (100%) rename tests/SIMULATION_MODELS/{snap_106_scf.param => snap_106.param} (100%) diff --git a/tests/04_FF/102_SNAP_base/INPUT b/tests/04_FF/102_SNAP_base/INPUT index 1928e9e50a2..59b27db4ddc 100644 --- a/tests/04_FF/102_SNAP_base/INPUT +++ b/tests/04_FF/102_SNAP_base/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file ../../SIMULATION_MODELS/snap_102_base.coeff -snap_param_file ../../SIMULATION_MODELS/snap_102_base.param +pot_file ../../SIMULATION_MODELS/snap_102.coeff +snap_param_file ../../SIMULATION_MODELS/snap_102.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/102_SNAP_base/README b/tests/04_FF/102_SNAP_base/README index ac442ea4791..ed605d2add5 100644 --- a/tests/04_FF/102_SNAP_base/README +++ b/tests/04_FF/102_SNAP_base/README @@ -1,7 +1,7 @@ CPU SNAP regression case with a two-atom Si periodic structure. -The example uses `../../SIMULATION_MODELS/snap_102_base.coeff` for the SNAP -coefficients and `../../SIMULATION_MODELS/snap_102_base.param` for the SNAP +The example uses `../../SIMULATION_MODELS/snap_102.coeff` for the SNAP +coefficients and `../../SIMULATION_MODELS/snap_102.param` for the SNAP parameters. The coefficient and parameter files are deterministic ABACUS-generated test diff --git a/tests/04_FF/103_SNAP_pbc/INPUT b/tests/04_FF/103_SNAP_pbc/INPUT index f052d2967da..2eee0601b68 100644 --- a/tests/04_FF/103_SNAP_pbc/INPUT +++ b/tests/04_FF/103_SNAP_pbc/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file ../../SIMULATION_MODELS/snap_103_pbc.coeff -snap_param_file ../../SIMULATION_MODELS/snap_103_pbc.param +pot_file ../../SIMULATION_MODELS/snap_103.coeff +snap_param_file ../../SIMULATION_MODELS/snap_103.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/103_SNAP_pbc/README b/tests/04_FF/103_SNAP_pbc/README index 9c3dc25e7d9..f6bf91f480f 100644 --- a/tests/04_FF/103_SNAP_pbc/README +++ b/tests/04_FF/103_SNAP_pbc/README @@ -5,5 +5,5 @@ but places the atoms on opposite sides of the periodic boundary. Their energy, force magnitude, and stress must match the unwrapped case. The periodic neighbor contributes through the MDCell ghost-force return path. -Model files: ../../SIMULATION_MODELS/snap_103_pbc.coeff and -../../SIMULATION_MODELS/snap_103_pbc.param. +Model files: ../../SIMULATION_MODELS/snap_103.coeff and +../../SIMULATION_MODELS/snap_103.param. diff --git a/tests/04_FF/104_SNAP_inner/INPUT b/tests/04_FF/104_SNAP_inner/INPUT index aa3f97ef195..57c29805ee8 100644 --- a/tests/04_FF/104_SNAP_inner/INPUT +++ b/tests/04_FF/104_SNAP_inner/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file ../../SIMULATION_MODELS/snap_104_inner.coeff -snap_param_file ../../SIMULATION_MODELS/snap_104_inner.param +pot_file ../../SIMULATION_MODELS/snap_104.coeff +snap_param_file ../../SIMULATION_MODELS/snap_104.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/104_SNAP_inner/README b/tests/04_FF/104_SNAP_inner/README index af552b75e40..4cdb3ae4c3b 100644 --- a/tests/04_FF/104_SNAP_inner/README +++ b/tests/04_FF/104_SNAP_inner/README @@ -9,5 +9,5 @@ The reference was cross-checked with LAMMPS SNAP (30 Mar 2026 development build, c46bbef): potential energy -0.24612388 eV, x forces -2.7962 and +2.7962 eV/Angstrom, and Pxx 3999.6081 bar. ABACUS reports Pxx in kbar. -Model files: ../../SIMULATION_MODELS/snap_104_inner.coeff and -../../SIMULATION_MODELS/snap_104_inner.param. +Model files: ../../SIMULATION_MODELS/snap_104.coeff and +../../SIMULATION_MODELS/snap_104.param. diff --git a/tests/04_FF/105_SNAP_quad/INPUT b/tests/04_FF/105_SNAP_quad/INPUT index 0ec21aca421..6b735a80ab4 100644 --- a/tests/04_FF/105_SNAP_quad/INPUT +++ b/tests/04_FF/105_SNAP_quad/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation md suffix autotest esolver_type snap -pot_file ../../SIMULATION_MODELS/snap_105_quad.coeff -snap_param_file ../../SIMULATION_MODELS/snap_105_quad.param +pot_file ../../SIMULATION_MODELS/snap_105.coeff +snap_param_file ../../SIMULATION_MODELS/snap_105.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/105_SNAP_quad/README b/tests/04_FF/105_SNAP_quad/README index bd87be609d0..add668c05ae 100644 --- a/tests/04_FF/105_SNAP_quad/README +++ b/tests/04_FF/105_SNAP_quad/README @@ -9,5 +9,5 @@ LAMMPS (30 Mar 2026 development build, c46bbef) gives total potential energy -122909.08 bar. ABACUS reports stress in kbar. The calculator unit test checks each force component and compares virial with an energy strain derivative. -Model files: ../../SIMULATION_MODELS/snap_105_quad.coeff and -../../SIMULATION_MODELS/snap_105_quad.param. +Model files: ../../SIMULATION_MODELS/snap_105.coeff and +../../SIMULATION_MODELS/snap_105.param. diff --git a/tests/04_FF/106_SNAP_scf/INPUT b/tests/04_FF/106_SNAP_scf/INPUT index f4a345fbac3..cf8103ce55e 100644 --- a/tests/04_FF/106_SNAP_scf/INPUT +++ b/tests/04_FF/106_SNAP_scf/INPUT @@ -2,8 +2,8 @@ INPUT_PARAMETERS calculation scf suffix autotest esolver_type snap -pot_file ../../SIMULATION_MODELS/snap_106_scf.coeff -snap_param_file ../../SIMULATION_MODELS/snap_106_scf.param +pot_file ../../SIMULATION_MODELS/snap_106.coeff +snap_param_file ../../SIMULATION_MODELS/snap_106.param cal_force 1 cal_stress 1 md_nstep 1 diff --git a/tests/04_FF/106_SNAP_scf/README b/tests/04_FF/106_SNAP_scf/README index fdeb4b03861..932d66466e6 100644 --- a/tests/04_FF/106_SNAP_scf/README +++ b/tests/04_FF/106_SNAP_scf/README @@ -3,5 +3,5 @@ model as case 105. The calculation enters the UnitCell solver path rather than the direct MDCell path. Energy, total force, and stress must match case 105 and the LAMMPS reference described there. -Model files: ../../SIMULATION_MODELS/snap_106_scf.coeff and -../../SIMULATION_MODELS/snap_106_scf.param. +Model files: ../../SIMULATION_MODELS/snap_106.coeff and +../../SIMULATION_MODELS/snap_106.param. diff --git a/tests/SIMULATION_MODELS/snap_102_base.coeff b/tests/SIMULATION_MODELS/snap_102.coeff similarity index 100% rename from tests/SIMULATION_MODELS/snap_102_base.coeff rename to tests/SIMULATION_MODELS/snap_102.coeff diff --git a/tests/SIMULATION_MODELS/snap_102_base.param b/tests/SIMULATION_MODELS/snap_102.param similarity index 100% rename from tests/SIMULATION_MODELS/snap_102_base.param rename to tests/SIMULATION_MODELS/snap_102.param diff --git a/tests/SIMULATION_MODELS/snap_103_pbc.coeff b/tests/SIMULATION_MODELS/snap_103.coeff similarity index 100% rename from tests/SIMULATION_MODELS/snap_103_pbc.coeff rename to tests/SIMULATION_MODELS/snap_103.coeff diff --git a/tests/SIMULATION_MODELS/snap_103_pbc.param b/tests/SIMULATION_MODELS/snap_103.param similarity index 100% rename from tests/SIMULATION_MODELS/snap_103_pbc.param rename to tests/SIMULATION_MODELS/snap_103.param diff --git a/tests/SIMULATION_MODELS/snap_104_inner.coeff b/tests/SIMULATION_MODELS/snap_104.coeff similarity index 100% rename from tests/SIMULATION_MODELS/snap_104_inner.coeff rename to tests/SIMULATION_MODELS/snap_104.coeff diff --git a/tests/SIMULATION_MODELS/snap_104_inner.param b/tests/SIMULATION_MODELS/snap_104.param similarity index 100% rename from tests/SIMULATION_MODELS/snap_104_inner.param rename to tests/SIMULATION_MODELS/snap_104.param diff --git a/tests/SIMULATION_MODELS/snap_105_quad.coeff b/tests/SIMULATION_MODELS/snap_105.coeff similarity index 100% rename from tests/SIMULATION_MODELS/snap_105_quad.coeff rename to tests/SIMULATION_MODELS/snap_105.coeff diff --git a/tests/SIMULATION_MODELS/snap_105_quad.param b/tests/SIMULATION_MODELS/snap_105.param similarity index 100% rename from tests/SIMULATION_MODELS/snap_105_quad.param rename to tests/SIMULATION_MODELS/snap_105.param diff --git a/tests/SIMULATION_MODELS/snap_106_scf.coeff b/tests/SIMULATION_MODELS/snap_106.coeff similarity index 100% rename from tests/SIMULATION_MODELS/snap_106_scf.coeff rename to tests/SIMULATION_MODELS/snap_106.coeff diff --git a/tests/SIMULATION_MODELS/snap_106_scf.param b/tests/SIMULATION_MODELS/snap_106.param similarity index 100% rename from tests/SIMULATION_MODELS/snap_106_scf.param rename to tests/SIMULATION_MODELS/snap_106.param From c8ae6fed86630bd492f983444f99450512fb4113 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 13:46:18 +0800 Subject: [PATCH 25/33] refactor: shorten SNAP Clebsch-Gordan filenames --- source/Makefile.Objects | 2 +- source/source_md/module_snap/CMakeLists.txt | 2 +- .../module_snap/{snap_clebsch_gordan.cpp => snap_cg.cpp} | 2 +- .../module_snap/{snap_clebsch_gordan.h => snap_cg.h} | 6 +++--- source/source_md/module_snap/snap_descriptor.h | 2 +- source/source_md/module_snap/unittest/CMakeLists.txt | 8 ++++---- .../{test_snap_clebsch_gordan.cpp => test_snap_cg.cpp} | 8 ++++---- 7 files changed, 15 insertions(+), 15 deletions(-) rename source/source_md/module_snap/{snap_clebsch_gordan.cpp => snap_cg.cpp} (99%) rename source/source_md/module_snap/{snap_clebsch_gordan.h => snap_cg.h} (93%) rename source/source_md/module_snap/unittest/{test_snap_clebsch_gordan.cpp => test_snap_cg.cpp} (79%) diff --git a/source/Makefile.Objects b/source/Makefile.Objects index 24c03c90d0b..64a5b386506 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -542,7 +542,7 @@ OBJS_MD=fire.o\ module_snap/snap_descriptor.o\ module_snap/snap_derivative.o\ module_snap/snap_model.o\ - module_snap/snap_clebsch_gordan.o\ + module_snap/snap_cg.o\ verlet.o\ OBJS_NEIGHBOR=sltk_atom.o\ diff --git a/source/source_md/module_snap/CMakeLists.txt b/source/source_md/module_snap/CMakeLists.txt index 9eec1beaee4..c10bf8ed1d0 100644 --- a/source/source_md/module_snap/CMakeLists.txt +++ b/source/source_md/module_snap/CMakeLists.txt @@ -5,7 +5,7 @@ target_sources( snap_descriptor.cpp snap_derivative.cpp snap_model.cpp - snap_clebsch_gordan.cpp + snap_cg.cpp ) if(BUILD_TESTING) diff --git a/source/source_md/module_snap/snap_clebsch_gordan.cpp b/source/source_md/module_snap/snap_cg.cpp similarity index 99% rename from source/source_md/module_snap/snap_clebsch_gordan.cpp rename to source/source_md/module_snap/snap_cg.cpp index f2d65865662..d711b22d199 100644 --- a/source/source_md/module_snap/snap_clebsch_gordan.cpp +++ b/source/source_md/module_snap/snap_cg.cpp @@ -1,4 +1,4 @@ -#include "snap_clebsch_gordan.h" +#include "snap_cg.h" #include diff --git a/source/source_md/module_snap/snap_clebsch_gordan.h b/source/source_md/module_snap/snap_cg.h similarity index 93% rename from source/source_md/module_snap/snap_clebsch_gordan.h rename to source/source_md/module_snap/snap_cg.h index 978c255d985..b0c4c188709 100644 --- a/source/source_md/module_snap/snap_clebsch_gordan.h +++ b/source/source_md/module_snap/snap_cg.h @@ -1,5 +1,5 @@ -#ifndef SNAP_CLEBSCH_GORDAN_H -#define SNAP_CLEBSCH_GORDAN_H +#ifndef SNAP_CG_H +#define SNAP_CG_H #include @@ -55,4 +55,4 @@ class ClebschGordanTable } // namespace SNAP } // namespace ModuleMD -#endif // SNAP_CLEBSCH_GORDAN_H +#endif // SNAP_CG_H diff --git a/source/source_md/module_snap/snap_descriptor.h b/source/source_md/module_snap/snap_descriptor.h index a20f495bac4..24be0ccd598 100644 --- a/source/source_md/module_snap/snap_descriptor.h +++ b/source/source_md/module_snap/snap_descriptor.h @@ -1,7 +1,7 @@ #ifndef SNAP_DESCRIPTOR_H #define SNAP_DESCRIPTOR_H -#include "snap_clebsch_gordan.h" +#include "snap_cg.h" #include "snap_model.h" #include diff --git a/source/source_md/module_snap/unittest/CMakeLists.txt b/source/source_md/module_snap/unittest/CMakeLists.txt index adf73f1ad39..86495fdb4ed 100644 --- a/source/source_md/module_snap/unittest/CMakeLists.txt +++ b/source/source_md/module_snap/unittest/CMakeLists.txt @@ -4,18 +4,18 @@ AddTest( ) AddTest( - TARGET MODULE_MD_SNAP_clebsch_gordan - SOURCES test_snap_clebsch_gordan.cpp ../snap_clebsch_gordan.cpp + TARGET MODULE_MD_SNAP_cg + SOURCES test_snap_cg.cpp ../snap_cg.cpp ) AddTest( TARGET MODULE_MD_SNAP_descriptor LIBS base device - SOURCES test_snap_descriptor.cpp ../snap_descriptor.cpp ../snap_derivative.cpp ../snap_model.cpp ../snap_clebsch_gordan.cpp + SOURCES test_snap_descriptor.cpp ../snap_descriptor.cpp ../snap_derivative.cpp ../snap_model.cpp ../snap_cg.cpp ) AddTest( TARGET MODULE_MD_SNAP_calculator LIBS base device - SOURCES test_snap_calculator.cpp ../snap_calculator.cpp ../snap_descriptor.cpp ../snap_derivative.cpp ../snap_model.cpp ../snap_clebsch_gordan.cpp + SOURCES test_snap_calculator.cpp ../snap_calculator.cpp ../snap_descriptor.cpp ../snap_derivative.cpp ../snap_model.cpp ../snap_cg.cpp ) diff --git a/source/source_md/module_snap/unittest/test_snap_clebsch_gordan.cpp b/source/source_md/module_snap/unittest/test_snap_cg.cpp similarity index 79% rename from source/source_md/module_snap/unittest/test_snap_clebsch_gordan.cpp rename to source/source_md/module_snap/unittest/test_snap_cg.cpp index 0639ccabfa3..238591418d8 100644 --- a/source/source_md/module_snap/unittest/test_snap_clebsch_gordan.cpp +++ b/source/source_md/module_snap/unittest/test_snap_cg.cpp @@ -1,4 +1,4 @@ -#include "../snap_clebsch_gordan.h" +#include "../snap_cg.h" #include @@ -7,13 +7,13 @@ namespace { -TEST(SnapClebschGordan, HighestWeightCoefficientIsOne) +TEST(SnapCG, HighestWeightCoefficientIsOne) { const ModuleMD::SNAP::ClebschGordanTable table(2); EXPECT_NEAR(table.coefficient(1, 1, 1, 1, 2, 2), 1.0, 1.0e-14); } -TEST(SnapClebschGordan, SingletHasExpectedSigns) +TEST(SnapCG, SingletHasExpectedSigns) { const ModuleMD::SNAP::ClebschGordanTable table(2); const double value = 1.0 / std::sqrt(2.0); @@ -21,7 +21,7 @@ TEST(SnapClebschGordan, SingletHasExpectedSigns) EXPECT_NEAR(table.coefficient(1, -1, 1, 1, 0, 0), -value, 1.0e-14); } -TEST(SnapClebschGordan, SelectionRulesReturnZero) +TEST(SnapCG, SelectionRulesReturnZero) { const ModuleMD::SNAP::ClebschGordanTable table(2); EXPECT_DOUBLE_EQ(table.coefficient(1, 1, 1, 1, 0, 0), 0.0); From f12fb78380548fce571d46293bfffe0d0bb9e9f5 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 14:46:46 +0800 Subject: [PATCH 26/33] fix: skip zero-weight SNAP neighbors in force derivatives --- source/source_esolver/esolver_snap.cpp | 15 ++++++------ .../source_md/module_snap/snap_derivative.cpp | 7 +++--- .../unittest/test_snap_calculator.cpp | 24 +++++++++++++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/source/source_esolver/esolver_snap.cpp b/source/source_esolver/esolver_snap.cpp index e55596b3ebc..2c738923b3d 100644 --- a/source/source_esolver/esolver_snap.cpp +++ b/source/source_esolver/esolver_snap.cpp @@ -172,19 +172,20 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) try for (std::size_t i = 0; i < mdcell.ghost_atoms().size(); ++i) { const std::array& value = contribution.forces()[nowned + i]; - mdcell.ghost_atoms()[i].force.set(value[0] * force_scale, - value[1] * force_scale, - value[2] * force_scale); + const double fx = value[0] * force_scale; + const double fy = value[1] * force_scale; + const double fz = value[2] * force_scale; + mdcell.ghost_atoms()[i].force.set(fx, fy, fz); } Parallel_Reduce::reduce_all(snap_potential_); Parallel_Reduce::reduce_all(snap_virial_.c, 9); for (int i = 0; i < nowned; ++i) { const std::array& value = contribution.forces()[static_cast(i)]; - owned_atoms[static_cast(i)].force.set( - value[0] * force_scale, - value[1] * force_scale, - value[2] * force_scale); + const double fx = value[0] * force_scale; + const double fy = value[1] * force_scale; + const double fz = value[2] * force_scale; + owned_atoms[static_cast(i)].force.set(fx, fy, fz); } return; } diff --git a/source/source_md/module_snap/snap_derivative.cpp b/source/source_md/module_snap/snap_derivative.cpp index cea61b8a31b..1c34bdd250a 100644 --- a/source/source_md/module_snap/snap_derivative.cpp +++ b/source/source_md/module_snap/snap_derivative.cpp @@ -130,7 +130,7 @@ UWithDerivative DescriptorEvaluator::compute_u_with_derivative(const Neighbor& n return result; } const SwitchValue switch_value = switching(distance.value, neighbor, cutoff_radius); - if (switch_value.value == 0.0) + if (switch_value.value == 0.0 || neighbor.weight == 0.0) { return result; } @@ -138,8 +138,9 @@ UWithDerivative DescriptorEvaluator::compute_u_with_derivative(const Neighbor& n { throw std::domain_error("SNAP neighbor distance must be greater than rmin0."); } - const Dual scale(switch_value.value * neighbor.weight, - switch_value.derivative * distance.derivative * neighbor.weight); + const double scale_value = switch_value.value * neighbor.weight; + const double scale_derivative = switch_value.derivative * distance.derivative * neighbor.weight; + const Dual scale(scale_value, scale_derivative); const Dual theta0 = (distance - parameters_.rmin) * parameters_.rfac0 * ModuleBase::PI / (cutoff_radius - parameters_.rmin); diff --git a/source/source_md/module_snap/unittest/test_snap_calculator.cpp b/source/source_md/module_snap/unittest/test_snap_calculator.cpp index 33ef835cd02..9baf346415d 100644 --- a/source/source_md/module_snap/unittest/test_snap_calculator.cpp +++ b/source/source_md/module_snap/unittest/test_snap_calculator.cpp @@ -306,6 +306,30 @@ TEST(SnapCalculator, InnerSwitchSkipsSingularRadius) } } +TEST(SnapCalculator, ZeroWeightSkipsInvalidRadius) +{ + ModuleMD::SNAP::ModelData model = make_model(); + model.parameters.rmin = 0.5; + const ModuleMD::SNAP::Calculator calculator(model); + ModuleMD::SNAP::Neighbor neighbor; + neighbor.x = 0.4; + neighbor.weight = 0.0; + const std::vector neighbors(1, neighbor); + const std::vector empty; + const double isolated_energy = calculator.compute(empty, 0).energy; + const ModuleMD::SNAP::ForceResult result = calculator.compute_with_analytic_force(neighbors, 0); + EXPECT_DOUBLE_EQ(result.energy.energy, isolated_energy); + for (int direction = 0; direction < 3; ++direction) + { + EXPECT_DOUBLE_EQ(result.center_force[static_cast(direction)], 0.0); + EXPECT_DOUBLE_EQ(result.neighbor_forces[0][static_cast(direction)], 0.0); + } + neighbor.weight = 1.0; + const std::vector active(1, neighbor); + EXPECT_THROW(calculator.compute(active, 0), std::domain_error); + EXPECT_THROW(calculator.compute_with_analytic_force(active, 0), std::domain_error); +} + TEST(SnapCalculator, AngularQuadraticForcesMatchLammpsAndStrain) { const ModuleMD::SNAP::Calculator calculator(make_angular_quadratic_model()); From 33c11ba92fabc41cb5928fb757ba1a09d99f1e33 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 14:47:44 +0800 Subject: [PATCH 27/33] test: cover angular chemical channel permutation and forces --- .../unittest/test_snap_calculator.cpp | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/source/source_md/module_snap/unittest/test_snap_calculator.cpp b/source/source_md/module_snap/unittest/test_snap_calculator.cpp index 9baf346415d..4ba71dc9b17 100644 --- a/source/source_md/module_snap/unittest/test_snap_calculator.cpp +++ b/source/source_md/module_snap/unittest/test_snap_calculator.cpp @@ -175,6 +175,63 @@ TEST(SnapCalculator, SupportsChemicalChannels) } } +TEST(SnapCalculator, ChemicalAngularChannelsFollowElementOrder) +{ + ModuleMD::SNAP::ModelData model = make_chemical_model(); + model.parameters.twojmax = 2; + model.coefficients.assign(2, std::vector(41, 0.0)); + // Bispectrum index 1 is angular; the channel triple (Si, C, Si) is 2. + const std::size_t original_index = 1 + 2 * 5 + 1; + model.coefficients[0][original_index] = 1.7; + const ModuleMD::SNAP::Calculator calculator(model); + + ModuleMD::SNAP::Neighbor silicon; + silicon.x = 1.0; + silicon.y = 0.1; + silicon.z = 0.2; + silicon.cutoff_radius = 4.5; + silicon.element_index = 0; + ModuleMD::SNAP::Neighbor carbon = silicon; + carbon.x = 0.3; + carbon.y = 1.1; + carbon.z = -0.4; + carbon.weight = 0.8; + carbon.element_index = 1; + const std::vector neighbors = {silicon, carbon}; + const ModuleMD::SNAP::ForceResult original = calculator.compute_with_analytic_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult finite = calculator.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); + + ModuleMD::SNAP::ModelData reordered = model; + reordered.parameters.elements = {"C", "Si"}; + reordered.parameters.element_weights = {0.8, 1.0}; + reordered.parameters.element_radii = {1.7, 2.25}; + reordered.coefficients.assign(2, std::vector(41, 0.0)); + // The same physical channel triple is (Si, C, Si) = (1, 0, 1) after reordering. + const std::size_t reordered_index = 1 + 5 * 5 + 1; + reordered.coefficients[1][reordered_index] = 1.7; + const ModuleMD::SNAP::Calculator reordered_calculator(reordered); + silicon.element_index = 1; + carbon.element_index = 0; + const std::vector reordered_neighbors = {silicon, carbon}; + const ModuleMD::SNAP::ForceResult permuted + = reordered_calculator.compute_with_analytic_force(reordered_neighbors, 1); + + EXPECT_NEAR(original.energy.energy, permuted.energy.energy, 1.0e-10); + for (std::size_t atom = 0; atom < neighbors.size(); ++atom) + { + double force_size = 0.0; + for (int direction = 0; direction < 3; ++direction) + { + const std::size_t component = static_cast(direction); + const double force = original.neighbor_forces[atom][component]; + force_size += std::abs(force); + EXPECT_NEAR(force, permuted.neighbor_forces[atom][component], 1.0e-10); + EXPECT_NEAR(force, finite.neighbor_forces[atom][component], 1.0e-5); + } + EXPECT_GT(force_size, 1.0e-6); + } +} + TEST(SnapCalculator, RejectsMismatchedCoefficientCount) { ModuleMD::SNAP::ModelData model = make_model(); From 0140a22cfb4ac0a85e32d874366b7a5a48fee721 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 14:51:00 +0800 Subject: [PATCH 28/33] perf: index SNAP Clebsch-Gordan coefficients --- source/source_md/module_snap/snap_cg.cpp | 15 ++++++--------- source/source_md/module_snap/snap_cg.h | 3 +++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/source/source_md/module_snap/snap_cg.cpp b/source/source_md/module_snap/snap_cg.cpp index d711b22d199..e26c95a63ad 100644 --- a/source/source_md/module_snap/snap_cg.cpp +++ b/source/source_md/module_snap/snap_cg.cpp @@ -41,6 +41,8 @@ ClebschGordanTable::ClebschGordanTable(const int twojmax) entry.j = j; entry.m = m; entry.value = coefficient_uncached(j1, m1, j2, m2, j, m); + const std::tuple key(j1, m1, j2, m2, j, m); + entry_indices_[key] = entries_.size(); entries_.push_back(entry); } } @@ -130,15 +132,10 @@ const ClebschGordanTable::Entry* ClebschGordanTable::find(const int j1, const int j, const int m) const { - for (std::size_t index = 0; index < entries_.size(); ++index) - { - const Entry& entry = entries_[index]; - if (entry.j1 == j1 && entry.m1 == m1 && entry.j2 == j2 && entry.m2 == m2 && entry.j == j && entry.m == m) - { - return &entry; - } - } - return nullptr; + const std::tuple key(j1, m1, j2, m2, j, m); + const std::map, std::size_t>::const_iterator found + = entry_indices_.find(key); + return found == entry_indices_.end() ? nullptr : &entries_[found->second]; } double ClebschGordanTable::coefficient(const int j1, diff --git a/source/source_md/module_snap/snap_cg.h b/source/source_md/module_snap/snap_cg.h index b0c4c188709..d194df83ca0 100644 --- a/source/source_md/module_snap/snap_cg.h +++ b/source/source_md/module_snap/snap_cg.h @@ -1,6 +1,8 @@ #ifndef SNAP_CG_H #define SNAP_CG_H +#include +#include #include namespace ModuleMD @@ -50,6 +52,7 @@ class ClebschGordanTable int twojmax_; std::vector entries_; + std::map, std::size_t> entry_indices_; }; } // namespace SNAP From 3c24ea202889180ece3a87fd508390d5b8bb5743 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 20:55:04 +0800 Subject: [PATCH 29/33] refactor: require explicit SNAP central element in accumulation --- source/source_md/module_snap/snap_descriptor.cpp | 5 ----- source/source_md/module_snap/snap_descriptor.h | 2 -- .../module_snap/unittest/test_snap_descriptor.cpp | 13 ++++++++----- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/source/source_md/module_snap/snap_descriptor.cpp b/source/source_md/module_snap/snap_descriptor.cpp index a0c33db3b64..9689f3a091a 100644 --- a/source/source_md/module_snap/snap_descriptor.cpp +++ b/source/source_md/module_snap/snap_descriptor.cpp @@ -162,11 +162,6 @@ std::vector > DescriptorEvaluator::compute_u(const Neighbor return result; } -std::vector > DescriptorEvaluator::accumulate_u(const std::vector& neighbors) const -{ - return accumulate_u(neighbors, 0); -} - std::vector > DescriptorEvaluator::accumulate_u(const std::vector& neighbors, const std::size_t central_element) const { diff --git a/source/source_md/module_snap/snap_descriptor.h b/source/source_md/module_snap/snap_descriptor.h index 24be0ccd598..c4a666ad2d1 100644 --- a/source/source_md/module_snap/snap_descriptor.h +++ b/source/source_md/module_snap/snap_descriptor.h @@ -39,8 +39,6 @@ class DescriptorEvaluator UWithDerivative compute_u_with_derivative(const Neighbor& neighbor, int direction) const; - std::vector > accumulate_u(const std::vector& neighbors) const; - std::vector > accumulate_u(const std::vector& neighbors, std::size_t central_element) const; diff --git a/source/source_md/module_snap/unittest/test_snap_descriptor.cpp b/source/source_md/module_snap/unittest/test_snap_descriptor.cpp index 0514dd4f6ae..176132000a7 100644 --- a/source/source_md/module_snap/unittest/test_snap_descriptor.cpp +++ b/source/source_md/module_snap/unittest/test_snap_descriptor.cpp @@ -33,7 +33,7 @@ TEST(SnapDescriptor, SelfContributionIsDiagonal) { const ModuleMD::SNAP::DescriptorEvaluator evaluator(make_parameters()); const std::vector neighbors; - const std::vector > u = evaluator.accumulate_u(neighbors); + const std::vector > u = evaluator.accumulate_u(neighbors, 0); EXPECT_DOUBLE_EQ(u[0].real(), 1.0); EXPECT_DOUBLE_EQ(u[0].imag(), 0.0); @@ -49,8 +49,9 @@ TEST(SnapDescriptor, OutsideCutoffDoesNotChangeEnvironment) ModuleMD::SNAP::Neighbor neighbor; neighbor.x = 5.0; const std::vector neighbors(1, neighbor); - const std::vector > u = evaluator.accumulate_u(neighbors); - const std::vector > self = evaluator.accumulate_u(std::vector()); + const std::vector > u = evaluator.accumulate_u(neighbors, 0); + const std::vector no_neighbors; + const std::vector > self = evaluator.accumulate_u(no_neighbors, 0); ASSERT_EQ(u.size(), self.size()); for (std::size_t i = 0; i < u.size(); ++i) @@ -67,7 +68,8 @@ TEST(SnapDescriptor, BispectrumIsFinite) neighbor.x = 1.2; neighbor.y = 0.4; neighbor.z = -0.8; - const std::vector > u = evaluator.accumulate_u(std::vector(1, neighbor)); + const std::vector neighbors(1, neighbor); + const std::vector > u = evaluator.accumulate_u(neighbors, 0); const std::vector bispectrum = evaluator.compute_bispectrum(u); for (std::size_t i = 0; i < bispectrum.size(); ++i) @@ -90,7 +92,8 @@ TEST(SnapDescriptor, MatchesLammpsSingleElementReference) neighbor.cutoff_radius = 4.0; neighbors.push_back(neighbor); } - const std::vector bispectrum = evaluator.compute_bispectrum(evaluator.accumulate_u(neighbors)); + const std::vector > u = evaluator.accumulate_u(neighbors, 0); + const std::vector bispectrum = evaluator.compute_bispectrum(u); const double reference[5] = { 13.0368348609, 15.0992648922, 11.7631725456, 13.7069739819, 6.07477849248}; ASSERT_EQ(bispectrum.size(), static_cast(5)); From 13ebc3e3c02d70e7113c5e64ac734c62cb46b74f Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 20:56:11 +0800 Subject: [PATCH 30/33] refactor: remove unused SNAP helpers and derivative values --- source/source_md/module_snap/snap_calculator.h | 5 ----- source/source_md/module_snap/snap_cg.cpp | 13 ------------- source/source_md/module_snap/snap_cg.h | 10 ---------- source/source_md/module_snap/snap_derivative.cpp | 2 -- source/source_md/module_snap/snap_descriptor.h | 1 - source/source_md/module_snap/snap_model.cpp | 9 --------- source/source_md/module_snap/snap_model.h | 1 - .../source_md/module_snap/unittest/test_snap_cg.cpp | 1 - .../module_snap/unittest/test_snap_model.cpp | 2 +- 9 files changed, 1 insertion(+), 43 deletions(-) diff --git a/source/source_md/module_snap/snap_calculator.h b/source/source_md/module_snap/snap_calculator.h index 3bbc9caead9..b09a547da41 100644 --- a/source/source_md/module_snap/snap_calculator.h +++ b/source/source_md/module_snap/snap_calculator.h @@ -39,11 +39,6 @@ class Calculator std::size_t central_element, double displacement) const; - std::size_t descriptor_size() const - { - return descriptor_size_; - } - private: ModelData model_; DescriptorEvaluator descriptor_evaluator_; diff --git a/source/source_md/module_snap/snap_cg.cpp b/source/source_md/module_snap/snap_cg.cpp index e26c95a63ad..e9f2ca0ffb7 100644 --- a/source/source_md/module_snap/snap_cg.cpp +++ b/source/source_md/module_snap/snap_cg.cpp @@ -149,18 +149,5 @@ double ClebschGordanTable::coefficient(const int j1, return entry == nullptr ? 0.0 : entry->value; } -double ClebschGordanTable::h_coefficient(const int j1, - const int m1, - const int mp1, - const int j2, - const int m2, - const int mp2, - const int j, - const int m, - const int mp) const -{ - return coefficient(j1, m1, j2, m2, j, m) * coefficient(j1, mp1, j2, mp2, j, mp); -} - } // namespace SNAP } // namespace ModuleMD diff --git a/source/source_md/module_snap/snap_cg.h b/source/source_md/module_snap/snap_cg.h index d194df83ca0..7198536882c 100644 --- a/source/source_md/module_snap/snap_cg.h +++ b/source/source_md/module_snap/snap_cg.h @@ -23,16 +23,6 @@ class ClebschGordanTable double coefficient(int j1, int m1, int j2, int m2, int j, int m) const; - double h_coefficient(int j1, - int m1, - int mp1, - int j2, - int m2, - int mp2, - int j, - int m, - int mp) const; - private: struct Entry { diff --git a/source/source_md/module_snap/snap_derivative.cpp b/source/source_md/module_snap/snap_derivative.cpp index 1c34bdd250a..0448560f056 100644 --- a/source/source_md/module_snap/snap_derivative.cpp +++ b/source/source_md/module_snap/snap_derivative.cpp @@ -123,7 +123,6 @@ UWithDerivative DescriptorEvaluator::compute_u_with_derivative(const Neighbor& n const double cutoff_radius = neighbor.cutoff_radius > 0.0 ? neighbor.cutoff_radius : parameters_.rcut; UWithDerivative result; - result.values.assign(u_size_, std::complex(0.0, 0.0)); result.derivatives.assign(u_size_, std::complex(0.0, 0.0)); if (distance.value <= 1.0e-14 || distance.value >= cutoff_radius) { @@ -182,7 +181,6 @@ UWithDerivative DescriptorEvaluator::compute_u_with_derivative(const Neighbor& n for (std::size_t i = 0; i < raw.size(); ++i) { const std::complex value = scale * raw[i]; - result.values[i] = std::complex(value.real().value, value.imag().value); result.derivatives[i] = std::complex(value.real().derivative, value.imag().derivative); } return result; diff --git a/source/source_md/module_snap/snap_descriptor.h b/source/source_md/module_snap/snap_descriptor.h index c4a666ad2d1..e3759d4eca5 100644 --- a/source/source_md/module_snap/snap_descriptor.h +++ b/source/source_md/module_snap/snap_descriptor.h @@ -26,7 +26,6 @@ struct Neighbor struct UWithDerivative { - std::vector > values; std::vector > derivatives; }; diff --git a/source/source_md/module_snap/snap_model.cpp b/source/source_md/module_snap/snap_model.cpp index 6df5673d859..08b85422c10 100644 --- a/source/source_md/module_snap/snap_model.cpp +++ b/source/source_md/module_snap/snap_model.cpp @@ -441,14 +441,5 @@ bool ModelData::load(const std::string& coefficient_file, return parameters.valid(error); } -std::size_t ModelData::coefficient_count() const -{ - if (coefficients.empty()) - { - return 0; - } - return coefficients[0].size(); -} - } // namespace SNAP } // namespace ModuleMD diff --git a/source/source_md/module_snap/snap_model.h b/source/source_md/module_snap/snap_model.h index 806018c19b3..29d7c2cbe83 100644 --- a/source/source_md/module_snap/snap_model.h +++ b/source/source_md/module_snap/snap_model.h @@ -43,7 +43,6 @@ struct ModelData const std::vector& requested_elements, std::string& error); - std::size_t coefficient_count() const; }; } // namespace SNAP diff --git a/source/source_md/module_snap/unittest/test_snap_cg.cpp b/source/source_md/module_snap/unittest/test_snap_cg.cpp index 238591418d8..022dda681d7 100644 --- a/source/source_md/module_snap/unittest/test_snap_cg.cpp +++ b/source/source_md/module_snap/unittest/test_snap_cg.cpp @@ -26,7 +26,6 @@ TEST(SnapCG, SelectionRulesReturnZero) const ModuleMD::SNAP::ClebschGordanTable table(2); EXPECT_DOUBLE_EQ(table.coefficient(1, 1, 1, 1, 0, 0), 0.0); EXPECT_DOUBLE_EQ(table.coefficient(1, 1, 1, -1, 2, 1), 0.0); - EXPECT_DOUBLE_EQ(table.h_coefficient(1, 1, 1, 1, -1, -1, 0, 0, 0), 0.5); } } // namespace diff --git a/source/source_md/module_snap/unittest/test_snap_model.cpp b/source/source_md/module_snap/unittest/test_snap_model.cpp index 691c56b550e..339b985c694 100644 --- a/source/source_md/module_snap/unittest/test_snap_model.cpp +++ b/source/source_md/module_snap/unittest/test_snap_model.cpp @@ -95,7 +95,7 @@ TEST(SnapModel, LoadsLammpsStyleCoefficientAndParameterFiles) std::string error; EXPECT_TRUE(model.load(coefficient_file, parameter_file, std::vector(1, "Si"), error)); EXPECT_TRUE(error.empty()); - ASSERT_EQ(model.coefficient_count(), static_cast(3)); + ASSERT_EQ(model.coefficients[0].size(), static_cast(3)); EXPECT_DOUBLE_EQ(model.parameters.element_weights[0], 1.0); EXPECT_DOUBLE_EQ(model.parameters.element_radii[0], 2.25); EXPECT_DOUBLE_EQ(model.parameters.rcut, 5.4); From 70f24172d553eefca99f4ed032845c44a8b8ed2a Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 21:05:10 +0800 Subject: [PATCH 31/33] fix: report SNAP failures from nonzero MPI ranks --- source/source_esolver/esolver_factory.cpp | 3 +- source/source_esolver/esolver_snap.cpp | 33 ++++---- source/source_esolver/esolver_snap.h | 4 +- .../unittest/test_snap_calculator.cpp | 17 ++-- tests/04_FF/CMakeLists.txt | 12 +++ tests/04_FF/check_snap_rank_error.py | 77 +++++++++++++++++++ 6 files changed, 125 insertions(+), 21 deletions(-) create mode 100644 tests/04_FF/check_snap_rank_error.py diff --git a/source/source_esolver/esolver_factory.cpp b/source/source_esolver/esolver_factory.cpp index d69af4ac73a..24c6c51edec 100644 --- a/source/source_esolver/esolver_factory.cpp +++ b/source/source_esolver/esolver_factory.cpp @@ -397,7 +397,8 @@ ESolver* init_esolver(const Input_para& inp) } else if (esolver_type == "snap_pot") { - return new ESolver_SNAP(inp.mdp.pot_file, inp.mdp.snap_param_file, GlobalV::ofs_running); + const int rank = GlobalV::MY_RANK; + return new ESolver_SNAP(inp.mdp.pot_file, inp.mdp.snap_param_file, GlobalV::ofs_running, rank); } throw std::invalid_argument("esolver_type = " + std::string(esolver_type) + ". Wrong in " + std::string(__FILE__) + " line " + std::to_string(__LINE__)); diff --git a/source/source_esolver/esolver_snap.cpp b/source/source_esolver/esolver_snap.cpp index 2c738923b3d..ce80d42f0ea 100644 --- a/source/source_esolver/esolver_snap.cpp +++ b/source/source_esolver/esolver_snap.cpp @@ -1,7 +1,6 @@ #include "esolver_snap.h" #include "source_base/constants.h" -#include "source_base/global_variable.h" #include "source_base/parallel_reduce.h" #include "source_cell/mdcell.h" #include "source_cell/module_neighlist/neighbor_search.h" @@ -19,17 +18,22 @@ namespace ModuleESolver namespace { -void fail(const std::string& message) +void fail(const std::string& message, const int rank) { + if (rank != 0) + { + std::cerr << "ESolver_SNAP rank " << rank << ": " << message << std::endl; + } ModuleBase::WARNING_QUIT("ESolver_SNAP", message); } -std::string full_path(const std::string& path) +std::string full_path(const std::string& path, const int rank) { char* resolved = ::realpath(path.c_str(), nullptr); if (resolved == nullptr) { - fail("Cannot resolve SNAP file path: " + path); + const std::string message = "Cannot resolve SNAP file path: " + path; + fail(message, rank); } const std::string result(resolved); std::free(resolved); @@ -63,8 +67,9 @@ ModuleMD::SNAP::Neighbor make_neighbor(const NeighborAtom& center, ESolver_SNAP::ESolver_SNAP(const std::string& coefficient_file, const std::string& parameter_file, - std::ofstream& running_log) - : coefficient_file_(coefficient_file), parameter_file_(parameter_file), running_log_(running_log) + std::ofstream& running_log, + const int rank) + : coefficient_file_(coefficient_file), parameter_file_(parameter_file), running_log_(running_log), rank_(rank) { classname = "ESolver_SNAP"; } @@ -74,13 +79,13 @@ void ESolver_SNAP::initialize(const std::vector& labels) std::string error; if (!model_.load(coefficient_file_, parameter_file_, labels, error)) { - fail(error); + fail(error, rank_); } - const std::string coefficient_path = full_path(coefficient_file_); - const std::string parameter_path = full_path(parameter_file_); + const std::string coefficient_path = full_path(coefficient_file_, rank_); + const std::string parameter_path = full_path(parameter_file_, rank_); running_log_ << " Read SNAP coefficient file: " << coefficient_path << std::endl; running_log_ << " Read SNAP parameter file: " << parameter_path << std::endl; - if (GlobalV::MY_RANK == 0) + if (rank_ == 0) { std::cout << " Read SNAP coefficient file: " << coefficient_path << std::endl; std::cout << " Read SNAP parameter file: " << parameter_path << std::endl; @@ -115,7 +120,7 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) try static_cast(istep); if (!calculator_) { - fail("SNAP solver was not initialized."); + fail("SNAP solver was not initialized.", rank_); } snap_potential_ = 0.0; snap_virial_.zero_out(); @@ -125,7 +130,7 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) try MDCell& mdcell = static_cast(cell); if (!mdcell.has_neighbor_search()) { - fail("MDCell neighbors must be prepared before ESolver_SNAP::runner()."); + fail("MDCell neighbors must be prepared before ESolver_SNAP::runner().", rank_); } std::vector& owned_atoms = mdcell.owned_atoms(); const std::vector& all_atoms = mdcell.neighbor_search().get_all_atoms(); @@ -148,7 +153,7 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) try const NeighborAtom& neighbor = all_atoms[static_cast(neighbor_index)]; if (neighbor.atom_type < 0 || static_cast(neighbor.atom_type) >= model_.parameters.elements.size()) { - fail("MDCell atom type is outside the SNAP element map."); + fail("MDCell atom type is outside the SNAP element map.", rank_); } neighbors.push_back(make_neighbor(center, neighbor, mdcell.lat0(), model_.parameters)); neighbor_indices.push_back(static_cast(neighbor_index)); @@ -248,7 +253,7 @@ void ESolver_SNAP::runner(BaseCell& cell, const int istep) try catch (const std::exception& error) { const std::string message = std::string("SNAP evaluation failed: ") + error.what(); - fail(message); + fail(message, rank_); } double ESolver_SNAP::cal_energy() diff --git a/source/source_esolver/esolver_snap.h b/source/source_esolver/esolver_snap.h index cad1b79af4a..6206750b201 100644 --- a/source/source_esolver/esolver_snap.h +++ b/source/source_esolver/esolver_snap.h @@ -17,7 +17,8 @@ class ESolver_SNAP : public ESolver public: ESolver_SNAP(const std::string& coefficient_file, const std::string& parameter_file, - std::ofstream& running_log); + std::ofstream& running_log, + int rank); void before_all_runners(BaseCell& cell, const Input_para& inp) override; void runner(BaseCell& cell, int istep) override; @@ -32,6 +33,7 @@ class ESolver_SNAP : public ESolver std::string coefficient_file_; std::string parameter_file_; std::ofstream& running_log_; + const int rank_; ModuleMD::SNAP::ModelData model_; std::unique_ptr calculator_; double snap_potential_ = 0.0; diff --git a/source/source_md/module_snap/unittest/test_snap_calculator.cpp b/source/source_md/module_snap/unittest/test_snap_calculator.cpp index 4ba71dc9b17..0eb2ff94b78 100644 --- a/source/source_md/module_snap/unittest/test_snap_calculator.cpp +++ b/source/source_md/module_snap/unittest/test_snap_calculator.cpp @@ -179,9 +179,10 @@ TEST(SnapCalculator, ChemicalAngularChannelsFollowElementOrder) { ModuleMD::SNAP::ModelData model = make_chemical_model(); model.parameters.twojmax = 2; - model.coefficients.assign(2, std::vector(41, 0.0)); - // Bispectrum index 1 is angular; the channel triple (Si, C, Si) is 2. - const std::size_t original_index = 1 + 2 * 5 + 1; + const std::vector zero_coefficients(41, 0.0); + model.coefficients.assign(2, zero_coefficients); + // Bispectrum index 2 couples the Si and C angular channels. + const std::size_t original_index = 1 + 2 * 5 + 2; model.coefficients[0][original_index] = 1.7; const ModuleMD::SNAP::Calculator calculator(model); @@ -200,14 +201,20 @@ TEST(SnapCalculator, ChemicalAngularChannelsFollowElementOrder) const std::vector neighbors = {silicon, carbon}; const ModuleMD::SNAP::ForceResult original = calculator.compute_with_analytic_force(neighbors, 0); const ModuleMD::SNAP::ForceResult finite = calculator.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); + ModuleMD::SNAP::Neighbor rotated_carbon = carbon; + rotated_carbon.x = carbon.y; + rotated_carbon.y = carbon.x; + const std::vector rotated_neighbors = {silicon, rotated_carbon}; + const double rotated_energy = calculator.compute(rotated_neighbors, 0).energy; + EXPECT_GT(std::abs(original.energy.energy - rotated_energy), 1.0e-6); ModuleMD::SNAP::ModelData reordered = model; reordered.parameters.elements = {"C", "Si"}; reordered.parameters.element_weights = {0.8, 1.0}; reordered.parameters.element_radii = {1.7, 2.25}; - reordered.coefficients.assign(2, std::vector(41, 0.0)); + reordered.coefficients.assign(2, zero_coefficients); // The same physical channel triple is (Si, C, Si) = (1, 0, 1) after reordering. - const std::size_t reordered_index = 1 + 5 * 5 + 1; + const std::size_t reordered_index = 1 + 5 * 5 + 2; reordered.coefficients[1][reordered_index] = 1.7; const ModuleMD::SNAP::Calculator reordered_calculator(reordered); silicon.element_index = 1; diff --git a/tests/04_FF/CMakeLists.txt b/tests/04_FF/CMakeLists.txt index 3041d6d389e..b6fed1438da 100644 --- a/tests/04_FF/CMakeLists.txt +++ b/tests/04_FF/CMakeLists.txt @@ -12,3 +12,15 @@ else() COMMAND ${BASH} ../integrate/Autotest.sh -a ${ABACUS_BIN_PATH} -n 4 -j auto WORKING_DIRECTORY ${ABACUS_TEST_DIR}/04_FF) endif() + +find_program(SNAP_TEST_PYTHON python3) +if(ENABLE_MPI AND SNAP_TEST_PYTHON AND MPIEXEC_EXECUTABLE) + add_test( + NAME 04_FF_SNAP_rank_error + COMMAND ${SNAP_TEST_PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/check_snap_rank_error.py + --abacus ${ABACUS_BIN_PATH} + --mpiexec ${MPIEXEC_EXECUTABLE} + --numproc-flag=${MPIEXEC_NUMPROC_FLAG} + --models ${ABACUS_TEST_DIR}/SIMULATION_MODELS) + set_tests_properties(04_FF_SNAP_rank_error PROPERTIES TIMEOUT 120) +endif() diff --git a/tests/04_FF/check_snap_rank_error.py b/tests/04_FF/check_snap_rank_error.py new file mode 100644 index 00000000000..91ae1bedc6a --- /dev/null +++ b/tests/04_FF/check_snap_rank_error.py @@ -0,0 +1,77 @@ +"""Check that a SNAP error on a nonzero MPI rank remains visible.""" + +import argparse +import os +from pathlib import Path +import subprocess +import tempfile + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--abacus", type=Path, required=True) + parser.add_argument("--mpiexec", type=Path, required=True) + parser.add_argument("--numproc-flag", default="-n") + parser.add_argument("--models", type=Path, required=True) + args = parser.parse_args() + + coefficient = (args.models / "snap_102.coeff").resolve() + with tempfile.TemporaryDirectory(prefix="abacus-snap-rank-") as scratch: + case = Path(scratch) + (case / "INPUT").write_text( + "INPUT_PARAMETERS\n" + "calculation md\n" + "suffix rank_error\n" + "esolver_type snap\n" + f"pot_file {coefficient}\n" + "snap_param_file snap.param\n" + "cal_force 1\n" + "md_nstep 1\n" + "md_type nve\n" + "init_vel 0\n", + encoding="utf-8", + ) + (case / "snap.param").write_text( + "rcutfac 4.9\n" + "twojmax 8\n" + "rfac0 0.99363\n" + "rmin0 0.2\n" + "bzeroflag 0\n", + encoding="utf-8", + ) + # Rank 0 owns the distant atom; rank 1 owns the close pair. + (case / "STRU").write_text( + "ATOMIC_SPECIES\nSi 28.0855 auto auto\n\n" + "LATTICE_CONSTANT\n1.0\n\n" + "LATTICE_VECTORS\n20.0 0.0 0.0\n0.0 20.0 0.0\n0.0 0.0 20.0\n\n" + "ATOMIC_POSITIONS\nCartesian\n\nSi\n0\n3\n" + "2.0 0.0 0.0 m 1 1 1\n" + "14.0 0.0 0.0 m 1 1 1\n" + "14.2 0.0 0.0 m 1 1 1\n", + encoding="utf-8", + ) + environment = os.environ.copy() + environment["OMP_NUM_THREADS"] = "1" + environment["OMPI_ALLOW_RUN_AS_ROOT"] = "1" + environment["OMPI_ALLOW_RUN_AS_ROOT_CONFIRM"] = "1" + command = [str(args.mpiexec), args.numproc_flag, "2", str(args.abacus)] + result = subprocess.run( + command, cwd=str(case), env=environment, text=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=90, + ) + expected = "ESolver_SNAP rank 1: SNAP evaluation failed: " \ + "SNAP neighbor distance must be greater than rmin0." + coefficient_messages = result.stdout.count(" Read SNAP coefficient file: ") + parameter_messages = result.stdout.count(" Read SNAP parameter file: ") + if (result.returncode == 0 or expected not in result.stderr + or "SNAP evaluation failed" in result.stdout + or coefficient_messages != 1 or parameter_messages != 1): + raise AssertionError( + "Expected one rank-0 file confirmation, a rank-1 SNAP error, " + f"and nonzero exit; got {result.returncode}.\n" + f"stdout:\n{result.stdout}\nstderr:\n{result.stderr}" + ) + + +if __name__ == "__main__": + main() From 74259aa101f164715d0f6e333a7c6c8f44916d4d Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 21:35:22 +0800 Subject: [PATCH 32/33] fix(snap): validate model data and reuse descriptor work --- source/source_esolver/esolver_snap.cpp | 10 ++- .../source_md/module_snap/snap_calculator.cpp | 77 +++++++++++++------ .../source_md/module_snap/snap_calculator.h | 4 + source/source_md/module_snap/snap_model.cpp | 21 +++++ .../unittest/test_snap_calculator.cpp | 31 +++++++- .../module_snap/unittest/test_snap_model.cpp | 31 ++++++++ 6 files changed, 148 insertions(+), 26 deletions(-) diff --git a/source/source_esolver/esolver_snap.cpp b/source/source_esolver/esolver_snap.cpp index ce80d42f0ea..a75321918ed 100644 --- a/source/source_esolver/esolver_snap.cpp +++ b/source/source_esolver/esolver_snap.cpp @@ -90,7 +90,15 @@ void ESolver_SNAP::initialize(const std::vector& labels) std::cout << " Read SNAP coefficient file: " << coefficient_path << std::endl; std::cout << " Read SNAP parameter file: " << parameter_path << std::endl; } - calculator_.reset(new ModuleMD::SNAP::Calculator(model_)); + try + { + calculator_.reset(new ModuleMD::SNAP::Calculator(model_)); + } + catch (const std::exception& error) + { + const std::string message = std::string("Invalid SNAP model: ") + error.what(); + fail(message, rank_); + } snap_virial_.create(3, 3); } diff --git a/source/source_md/module_snap/snap_calculator.cpp b/source/source_md/module_snap/snap_calculator.cpp index 5e33e78094d..86440767fd7 100644 --- a/source/source_md/module_snap/snap_calculator.cpp +++ b/source/source_md/module_snap/snap_calculator.cpp @@ -26,7 +26,22 @@ Calculator::Calculator(const ModelData& model) { if (model_.coefficients[element].size() != expected_count) { - throw std::invalid_argument("SNAP coefficient count does not match the descriptor size."); + throw std::invalid_argument("SNAP coefficient count for element " + model_.parameters.elements[element] + + " does not match the descriptor size: expected " + + std::to_string(expected_count) + ", found " + + std::to_string(model_.coefficients[element].size()) + "."); + } + } + if (model_.parameters.bzero_flag) + { + const std::vector empty_neighbors; + bzero_.reserve(model_.coefficients.size()); + for (std::size_t element = 0; element < model_.coefficients.size(); ++element) + { + const std::vector > self_u + = descriptor_evaluator_.accumulate_u(empty_neighbors, element); + const std::vector self_bispectrum = descriptor_evaluator_.compute_bispectrum(self_u); + bzero_.push_back(self_bispectrum); } } } @@ -38,17 +53,20 @@ EnergyResult Calculator::compute(const std::vector& neighbors, const s throw std::out_of_range("SNAP central element index is outside the model."); } + const std::vector > u = descriptor_evaluator_.accumulate_u(neighbors, central_element); + return compute_from_u(u, central_element); +} + +EnergyResult Calculator::compute_from_u(const std::vector >& u, + const std::size_t central_element) const +{ EnergyResult result; - result.descriptor = descriptor_evaluator_.compute_bispectrum( - descriptor_evaluator_.accumulate_u(neighbors, central_element)); + result.descriptor = descriptor_evaluator_.compute_bispectrum(u); if (model_.parameters.bzero_flag) { - const std::vector bzero = - descriptor_evaluator_.compute_bispectrum( - descriptor_evaluator_.accumulate_u(std::vector(), central_element)); for (std::size_t index = 0; index < result.descriptor.size(); ++index) { - result.descriptor[index] -= bzero[index]; + result.descriptor[index] -= bzero_[central_element][index]; } } const std::vector& coefficients = model_.coefficients[central_element]; @@ -80,11 +98,36 @@ ForceResult Calculator::compute_with_analytic_force(const std::vector& throw std::out_of_range("SNAP central element index is outside the model."); } ForceResult result; - result.energy = compute(neighbors, central_element); + const std::vector > u = descriptor_evaluator_.accumulate_u(neighbors, central_element); + result.energy = compute_from_u(u, central_element); result.center_force.assign(3, 0.0); result.neighbor_forces.assign(neighbors.size(), std::vector(3, 0.0)); const std::vector& coefficients = model_.coefficients[central_element]; - const std::vector > u = descriptor_evaluator_.accumulate_u(neighbors, central_element); + std::vector force_coefficients(result.energy.descriptor.size(), 0.0); + for (std::size_t i = 0; i < force_coefficients.size(); ++i) + { + force_coefficients[i] = coefficients[i + 1]; + } + if (model_.parameters.quadratic_flag) + { + std::size_t coefficient = force_coefficients.size() + 1; + for (std::size_t i = 0; i < force_coefficients.size(); ++i) + { + for (std::size_t j = i; j < force_coefficients.size(); ++j) + { + const double value = coefficients[coefficient++]; + if (i == j) + { + force_coefficients[i] += value * result.energy.descriptor[i]; + } + else + { + force_coefficients[i] += value * result.energy.descriptor[j]; + force_coefficients[j] += value * result.energy.descriptor[i]; + } + } + } + } for (std::size_t neighbor_index = 0; neighbor_index < neighbors.size(); ++neighbor_index) { for (int direction = 0; direction < 3; ++direction) @@ -105,21 +148,7 @@ ForceResult Calculator::compute_with_analytic_force(const std::vector& double derivative = 0.0; for (std::size_t index = 0; index < db.size(); ++index) { - derivative += coefficients[index + 1] * db[index]; - } - if (model_.parameters.quadratic_flag) - { - std::size_t coefficient = db.size() + 1; - for (std::size_t i = 0; i < db.size(); ++i) - { - for (std::size_t j = i; j < db.size(); ++j) - { - const double factor = i == j ? 0.5 : 1.0; - derivative += coefficients[coefficient++] * factor - * (db[i] * result.energy.descriptor[j] - + result.energy.descriptor[i] * db[j]); - } - } + derivative += force_coefficients[index] * db[index]; } result.center_force[static_cast(direction)] += derivative; result.neighbor_forces[neighbor_index][static_cast(direction)] = -derivative; diff --git a/source/source_md/module_snap/snap_calculator.h b/source/source_md/module_snap/snap_calculator.h index b09a547da41..077cd4f5ca3 100644 --- a/source/source_md/module_snap/snap_calculator.h +++ b/source/source_md/module_snap/snap_calculator.h @@ -40,9 +40,13 @@ class Calculator double displacement) const; private: + EnergyResult compute_from_u(const std::vector >& u, + std::size_t central_element) const; + ModelData model_; DescriptorEvaluator descriptor_evaluator_; std::size_t descriptor_size_; + std::vector > bzero_; }; class CellAccumulator diff --git a/source/source_md/module_snap/snap_model.cpp b/source/source_md/module_snap/snap_model.cpp index 08b85422c10..922075a480c 100644 --- a/source/source_md/module_snap/snap_model.cpp +++ b/source/source_md/module_snap/snap_model.cpp @@ -192,6 +192,12 @@ bool ModelData::load(const std::string& coefficient_file, error = "Invalid SNAP coefficient file header."; return false; } + std::string extra; + if (header >> extra) + { + error = "Unexpected extra value in SNAP coefficient file header."; + return false; + } std::vector found(parameters.elements.size(), false); parameters.element_weights.assign(parameters.elements.size(), 0.0); @@ -213,6 +219,11 @@ bool ModelData::load(const std::string& coefficient_file, error = "Invalid SNAP element line."; return false; } + if (element_line >> extra) + { + error = "Unexpected extra value in SNAP element line: " + element; + return false; + } std::size_t element_index = parameters.elements.size(); for (std::size_t i = 0; i < parameters.elements.size(); ++i) { @@ -236,6 +247,11 @@ bool ModelData::load(const std::string& coefficient_file, error = "Invalid SNAP coefficient value."; return false; } + if (!std::isfinite(values[static_cast(coefficient)]) || value_line >> extra) + { + error = "Invalid or extra SNAP coefficient value for element: " + element; + return false; + } } if (element_index < parameters.elements.size()) { @@ -250,6 +266,11 @@ bool ModelData::load(const std::string& coefficient_file, coefficients[element_index] = values; } } + if (next_data_line(coeff_stream, line)) + { + error = "Unexpected data after the SNAP coefficient blocks."; + return false; + } for (std::size_t i = 0; i < found.size(); ++i) { if (!found[i]) diff --git a/source/source_md/module_snap/unittest/test_snap_calculator.cpp b/source/source_md/module_snap/unittest/test_snap_calculator.cpp index 0eb2ff94b78..70dd85dae55 100644 --- a/source/source_md/module_snap/unittest/test_snap_calculator.cpp +++ b/source/source_md/module_snap/unittest/test_snap_calculator.cpp @@ -243,7 +243,36 @@ TEST(SnapCalculator, RejectsMismatchedCoefficientCount) { ModuleMD::SNAP::ModelData model = make_model(); model.coefficients[0].push_back(4.0); - EXPECT_THROW(ModuleMD::SNAP::Calculator calculator(model), std::invalid_argument); + try + { + const ModuleMD::SNAP::Calculator calculator(model); + FAIL() << "Expected a coefficient-count error"; + } + catch (const std::invalid_argument& error) + { + EXPECT_NE(std::string(error.what()).find("expected 2, found 3"), std::string::npos); + } +} + +TEST(SnapCalculator, CachedSelfDescriptorMatchesEnergyAndForce) +{ + ModuleMD::SNAP::ModelData model = make_model(); + const ModuleMD::SNAP::Calculator calculator(model); + ModuleMD::SNAP::Neighbor neighbor; + neighbor.x = 1.0; + neighbor.y = 0.4; + const std::vector neighbors(1, neighbor); + const ModuleMD::SNAP::EnergyResult energy = calculator.compute(neighbors, 0); + const ModuleMD::SNAP::ForceResult analytic = calculator.compute_with_analytic_force(neighbors, 0); + const ModuleMD::SNAP::ForceResult finite = calculator.compute_with_finite_difference_force(neighbors, 0, 1.0e-6); + EXPECT_DOUBLE_EQ(energy.energy, analytic.energy.energy); + ASSERT_EQ(energy.descriptor.size(), analytic.energy.descriptor.size()); + EXPECT_DOUBLE_EQ(energy.descriptor[0], analytic.energy.descriptor[0]); + for (int direction = 0; direction < 3; ++direction) + { + const std::size_t index = static_cast(direction); + EXPECT_NEAR(analytic.neighbor_forces[0][index], finite.neighbor_forces[0][index], 1.0e-6); + } } TEST(SnapCalculator, RejectsInvalidCentralElement) diff --git a/source/source_md/module_snap/unittest/test_snap_model.cpp b/source/source_md/module_snap/unittest/test_snap_model.cpp index 339b985c694..97de38ae94d 100644 --- a/source/source_md/module_snap/unittest/test_snap_model.cpp +++ b/source/source_md/module_snap/unittest/test_snap_model.cpp @@ -234,4 +234,35 @@ TEST(SnapModel, ReadsInnerSwitchAndRejectsUnknownParameter) std::remove(parameter_file.c_str()); } +TEST(SnapModel, RejectsExtraCoefficientFileData) +{ + const std::string coefficient_file = testing::TempDir() + "snap_extra_coeff.txt"; + const std::string parameter_file = testing::TempDir() + "snap_extra_param.txt"; + { + std::ofstream output(parameter_file.c_str()); + output << "rcutfac 1.0\ntwojmax 0\n"; + } + const std::vector contents = { + "1 2 extra\nSi 2.0 1.0\n0.0\n1.0\n", + "1 2\nSi 2.0 1.0 extra\n0.0\n1.0\n", + "1 2\nSi 2.0 1.0\n0.0 extra\n1.0\n", + "1 2\nSi 2.0 1.0\n0.0\n1.0\nextra\n"}; + const std::vector expected = { + "header", "element line", "coefficient value", "after the SNAP coefficient blocks"}; + for (std::size_t i = 0; i < contents.size(); ++i) + { + { + std::ofstream output(coefficient_file.c_str()); + output << contents[i]; + } + ModuleMD::SNAP::ModelData model; + std::string error; + const std::vector elements(1, "Si"); + EXPECT_FALSE(model.load(coefficient_file, parameter_file, elements, error)); + EXPECT_NE(error.find(expected[i]), std::string::npos) << error; + } + std::remove(coefficient_file.c_str()); + std::remove(parameter_file.c_str()); +} + } // namespace From 0a4bda26fbd99f852856398f413673d95f6526b3 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Mon, 2 Nov 2026 21:47:58 +0800 Subject: [PATCH 33/33] fix(snap): reject radial factors above one --- docs/advanced/md.md | 3 ++- source/source_md/module_snap/snap_model.cpp | 4 +-- .../module_snap/unittest/test_snap_model.cpp | 27 +++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/advanced/md.md b/docs/advanced/md.md index b7d7803ea9f..98d17de43ba 100644 --- a/docs/advanced/md.md +++ b/docs/advanced/md.md @@ -116,4 +116,5 @@ LAMMPS `pair_coeff` mappings. The CPU implementation accepts but does not use the LAMMPS GPU execution options `chunksize` and `parallelthresh`. Unknown SNAP parameter keywords are rejected. Each element-pair cutoff must exceed `rmin0`; a contributing neighbor -at or below `rmin0` causes an error. +at or below `rmin0` causes an error. The radial mapping parameter `rfac0` must +satisfy `0 < rfac0 <= 1` so that its angle does not cross pi inside a pair cutoff. diff --git a/source/source_md/module_snap/snap_model.cpp b/source/source_md/module_snap/snap_model.cpp index 922075a480c..caf8caa866a 100644 --- a/source/source_md/module_snap/snap_model.cpp +++ b/source/source_md/module_snap/snap_model.cpp @@ -111,9 +111,9 @@ bool ModelParameters::valid(std::string& error) const error = "SNAP rmin must satisfy 0 <= rmin < rcut."; return false; } - if (!std::isfinite(rfac0) || rfac0 <= 0.0) + if (!std::isfinite(rfac0) || rfac0 <= 0.0 || rfac0 > 1.0) { - error = "SNAP rfac0 must be finite and positive."; + error = "SNAP rfac0 must satisfy 0 < rfac0 <= 1."; return false; } if (twojmax < 0) diff --git a/source/source_md/module_snap/unittest/test_snap_model.cpp b/source/source_md/module_snap/unittest/test_snap_model.cpp index 97de38ae94d..118f4fa6a9d 100644 --- a/source/source_md/module_snap/unittest/test_snap_model.cpp +++ b/source/source_md/module_snap/unittest/test_snap_model.cpp @@ -56,6 +56,26 @@ TEST(SnapModel, RejectsInvalidRadialRange) EXPECT_FALSE(error.empty()); } +TEST(SnapModel, ValidatesRfac0Range) +{ + ModuleMD::SNAP::ModelParameters parameters; + parameters.rcut = 4.5; + parameters.rcutfac = 1.0; + parameters.elements.push_back("Si"); + parameters.element_weights.push_back(1.0); + parameters.element_radii.push_back(2.25); + std::string error; + + parameters.rfac0 = 1.0; + EXPECT_TRUE(parameters.valid(error)) << error; + parameters.rfac0 = 0.0; + EXPECT_FALSE(parameters.valid(error)); + EXPECT_NE(error.find("0 < rfac0 <= 1"), std::string::npos); + parameters.rfac0 = 1.2; + EXPECT_FALSE(parameters.valid(error)); + EXPECT_NE(error.find("0 < rfac0 <= 1"), std::string::npos); +} + TEST(SnapModel, RejectsRminOutsideSmallPairCutoff) { ModuleMD::SNAP::ModelParameters parameters; @@ -101,6 +121,13 @@ TEST(SnapModel, LoadsLammpsStyleCoefficientAndParameterFiles) EXPECT_DOUBLE_EQ(model.parameters.rcut, 5.4); EXPECT_DOUBLE_EQ(model.coefficients[0][1], 1.25); + { + std::ofstream output(parameter_file.c_str()); + output << "rcutfac 1.2\ntwojmax 4\nrfac0 1.2\n"; + } + EXPECT_FALSE(model.load(coefficient_file, parameter_file, std::vector(1, "Si"), error)); + EXPECT_NE(error.find("0 < rfac0 <= 1"), std::string::npos); + std::remove(coefficient_file.c_str()); std::remove(parameter_file.c_str()); }