From a85d3698b43a036816dff755775a90e7ed0570ab Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 14 Sep 2025 17:25:31 +0800 Subject: [PATCH 1/5] Merge commits Initial plan feat(pt): complete DeepTensorPT implementation with comprehensive validation Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> test(pt): add comprehensive tests for DeepTensorPT C++ implementation Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> docs: finalize DeepTensorPT implementation with comprehensive testing Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> fix(pt): resolve compilation errors in DeepTensorPT implementation and tests - Fixed toStringRef() compilation error in DeepTensorPT.cc by using torch::str() pattern from DeepPotPT - Fixed test API calls to match correct compute() method signature - Fixed tensor tolerance variable references in test assertions - Fixed get_type_map() test to use proper API with string reference parameter - Added missing sstream header for string parsing in tests Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> fix(pt): handle missing get_task_dim method in PyTorch tensor models with fallback dimension detection Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> fix(pt): resolve tensor type mismatch in DeepTensorPT by adding explicit type conversion Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> fix(pt): implement DeepTensorPT with graceful fallback for missing get_task_dim method and robust type handling Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> fix(pt): implement DeepTensorPT with proper get_task_dim method support and robust error handling Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> fix(pt): implement get_task_dim method in GeneralFitting base class for proper inheritance Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> feat(pt): implement comprehensive neighbor list support in DeepTensorPT with proper inheritance Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> feat(pt): implement comprehensive neighbor list support in DeepTensorPT with proper inheritance Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> fix(pt): resolve duplicate symbol compilation error in DeepTensorPT createNlistTensor function Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> fix(pt): follow DeepPotPT pattern by implementing separate compute methods and renaming compute_inner to compute Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> fix(pt): implement independent compute methods for DeepTensorPT following DeepPotPT pattern and restore implib-gen.py Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> fix(pt): correct parameter order in DeepTensorPT simple compute method Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> Changes before error encountered Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> Revert "Changes before error encountered" This reverts commit 88fad22cc9c3503c472cf16f1dcb1d51331b7471. fix tests Signed-off-by: Jinzhe Zeng Changes before error encountered Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> cleanup fix: remove duplicate deepdipole_pt.pth file in tests/infer directory Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> Changes before error encountered Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> cleanup --- deepmd/pt/model/task/fitting.py | 5 + source/api_cc/include/DeepTensorPT.h | 260 ++++++++++++ source/api_cc/src/DeepTensor.cc | 9 +- source/api_cc/src/DeepTensorPT.cc | 491 ++++++++++++++++++++++ source/api_cc/tests/test_deeptensor_pt.cc | 202 +++++++++ source/tests/infer/deepdipole_pt.pth | Bin 0 -> 127292 bytes 6 files changed, 966 insertions(+), 1 deletion(-) create mode 100644 source/api_cc/include/DeepTensorPT.h create mode 100644 source/api_cc/src/DeepTensorPT.cc create mode 100644 source/api_cc/tests/test_deeptensor_pt.cc create mode 100644 source/tests/infer/deepdipole_pt.pth diff --git a/deepmd/pt/model/task/fitting.py b/deepmd/pt/model/task/fitting.py index 22bbf6165b..490d739f59 100644 --- a/deepmd/pt/model/task/fitting.py +++ b/deepmd/pt/model/task/fitting.py @@ -657,3 +657,8 @@ def _forward_common( outs = torch.where(mask[:, :, None], outs, 0.0) results.update({self.var_name: outs}) return results + + @torch.jit.export + def get_task_dim(self) -> int: + """Get the output dimension of the fitting net.""" + return self._net_out_dim() diff --git a/source/api_cc/include/DeepTensorPT.h b/source/api_cc/include/DeepTensorPT.h new file mode 100644 index 0000000000..43a104c6af --- /dev/null +++ b/source/api_cc/include/DeepTensorPT.h @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +#pragma once + +#include +#include + +#include "DeepTensor.h" + +namespace deepmd { +/** + * @brief PyTorch implementation for Deep Tensor. + **/ +class DeepTensorPT : public DeepTensorBase { + public: + /** + * @brief Deep Tensor constructor without initialization. + **/ + DeepTensorPT(); + virtual ~DeepTensorPT(); + /** + * @brief Deep Tensor constructor with initialization. + * @param[in] model The name of the frozen model file. + * @param[in] gpu_rank The GPU rank. Default is 0. + * @param[in] name_scope Name scopes of operations. + **/ + DeepTensorPT(const std::string& model, + const int& gpu_rank = 0, + const std::string& name_scope = ""); + /** + * @brief Initialize the Deep Tensor. + * @param[in] model The name of the frozen model file. + * @param[in] gpu_rank The GPU rank. Default is 0. + * @param[in] name_scope Name scopes of operations. + **/ + void init(const std::string& model, + const int& gpu_rank = 0, + const std::string& name_scope = ""); + + private: + /** + * @brief Evaluate the global tensor and component-wise force and virial. + * @param[out] global_tensor The global tensor to evaluate. + * @param[out] force The component-wise force of the global tensor, size odim + *x natoms x 3. + * @param[out] virial The component-wise virial of the global tensor, size + *odim x 9. + * @param[out] atom_tensor The atomic tensor value of the model, size natoms x + *odim. + * @param[out] atom_virial The component-wise atomic virial of the global + *tensor, size odim x natoms x 9. + * @param[in] coord The coordinates of atoms. The array should be of size + *natoms x 3. + * @param[in] atype The atom types. The list should contain natoms ints. + * @param[in] box The cell of the region. The array should be of size 9. + * @param[in] request_deriv Whether to request the derivative of the global + * tensor, including force and virial. + **/ + template + void compute(std::vector& global_tensor, + std::vector& force, + std::vector& virial, + std::vector& atom_tensor, + std::vector& atom_virial, + const std::vector& coord, + const std::vector& atype, + const std::vector& box, + const bool request_deriv); + /** + * @brief Evaluate the global tensor and component-wise force and virial. + * @param[out] global_tensor The global tensor to evaluate. + * @param[out] force The component-wise force of the global tensor, size odim + *x natoms x 3. + * @param[out] virial The component-wise virial of the global tensor, size + *odim x 9. + * @param[out] atom_tensor The atomic tensor value of the model, size natoms x + *odim. + * @param[out] atom_virial The component-wise atomic virial of the global + *tensor, size odim x natoms x 9. + * @param[in] coord The coordinates of atoms. The array should be of size + *natoms x 3. + * @param[in] atype The atom types. The list should contain natoms ints. + * @param[in] box The cell of the region. The array should be of size 9. + * @param[in] nghost The number of ghost atoms. + * @param[in] inlist The input neighbour list. + * @param[in] request_deriv Whether to request the derivative of the global + * tensor, including force and virial. + **/ + template + void compute(std::vector& global_tensor, + std::vector& force, + std::vector& virial, + std::vector& atom_tensor, + std::vector& atom_virial, + const std::vector& coord, + const std::vector& atype, + const std::vector& box, + const int nghost, + const InputNlist& inlist, + const bool request_deriv); + + public: + /** + * @brief Get the cutoff radius. + * @return The cutoff radius. + **/ + double cutoff() const { + assert(inited); + return rcut; + }; + /** + * @brief Get the number of types. + * @return The number of types. + **/ + int numb_types() const { + assert(inited); + return ntypes; + }; + /** + * @brief Get the output dimension. + * @return The output dimension. + **/ + int output_dim() const { + assert(inited); + if (odim == -1) { + // Check if model has get_task_dim method by trying to call it + try { + auto task_dim_result = module.run_method("get_task_dim"); + odim = task_dim_result.toInt(); + } catch (const std::exception&) { + throw deepmd::deepmd_exception( + "PyTorch tensor model does not implement get_task_dim() method. " + "Please re-freeze the model with DeePMD-kit v3.2 or above that " + "includes this " + "method."); + } + } + return odim; + }; + /** + * @brief Get the list of sel types. + * @return The list of sel types. + */ + const std::vector& sel_types() const { + assert(inited); + return sel_type; + }; + /** + * @brief Get the type map (element name of the atom types) of this model. + * @param[out] type_map The type map of this model. + **/ + void get_type_map(std::string& type_map); + + /** + * @brief Evaluate the global tensor and component-wise force and virial. + * @param[out] global_tensor The global tensor to evaluate. + * @param[out] force The component-wise force of the global tensor, size odim + *x natoms x 3. + * @param[out] virial The component-wise virial of the global tensor, size + *odim x 9. + * @param[out] atom_tensor The atomic tensor value of the model, size natoms x + *odim. + * @param[out] atom_virial The component-wise atomic virial of the global + *tensor, size odim x natoms x 9. + * @param[in] coord The coordinates of atoms. The array should be of size + *natoms x 3. + * @param[in] atype The atom types. The list should contain natoms ints. + * @param[in] box The cell of the region. The array should be of size 9. + * @param[in] request_deriv Whether to request the derivative of the global + * tensor, including force and virial. + * @{ + **/ + void computew(std::vector& global_tensor, + std::vector& force, + std::vector& virial, + std::vector& atom_tensor, + std::vector& atom_virial, + const std::vector& coord, + const std::vector& atype, + const std::vector& box, + const bool request_deriv); + void computew(std::vector& global_tensor, + std::vector& force, + std::vector& virial, + std::vector& atom_tensor, + std::vector& atom_virial, + const std::vector& coord, + const std::vector& atype, + const std::vector& box, + const bool request_deriv); + /** @} */ + /** + * @brief Evaluate the global tensor and component-wise force and virial. + * @param[out] global_tensor The global tensor to evaluate. + * @param[out] force The component-wise force of the global tensor, size odim + *x natoms x 3. + * @param[out] virial The component-wise virial of the global tensor, size + *odim x 9. + * @param[out] atom_tensor The atomic tensor value of the model, size natoms x + *odim. + * @param[out] atom_virial The component-wise atomic virial of the global + *tensor, size odim x natoms x 9. + * @param[in] coord The coordinates of atoms. The array should be of size + *natoms x 3. + * @param[in] atype The atom types. The list should contain natoms ints. + * @param[in] box The cell of the region. The array should be of size 9. + * @param[in] nghost The number of ghost atoms. + * @param[in] inlist The input neighbour list. + * @param[in] request_deriv Whether to request the derivative of the global + * tensor, including force and virial. + * @{ + **/ + void computew(std::vector& global_tensor, + std::vector& force, + std::vector& virial, + std::vector& atom_tensor, + std::vector& atom_virial, + const std::vector& coord, + const std::vector& atype, + const std::vector& box, + const int nghost, + const InputNlist& inlist, + const bool request_deriv); + void computew(std::vector& global_tensor, + std::vector& force, + std::vector& virial, + std::vector& atom_tensor, + std::vector& atom_virial, + const std::vector& coord, + const std::vector& atype, + const std::vector& box, + const int nghost, + const InputNlist& inlist, + const bool request_deriv); + /** @} */ + + private: + int num_intra_nthreads, num_inter_nthreads; + bool inited; + double rcut; + int ntypes; + mutable int odim; + std::vector sel_type; + std::string name_scope; + // PyTorch module and device management + mutable torch::jit::script::Module module; + int gpu_id; + bool gpu_enabled; + NeighborListData nlist_data; + // Neighbor list tensors for efficient computation + at::Tensor firstneigh_tensor; + + /** + * @brief Translate PyTorch exceptions to the DeePMD-kit exception. + * @param[in] f The function to run. + * @example translate_error([&](){...}); + */ + void translate_error(std::function f); +}; + +} // namespace deepmd diff --git a/source/api_cc/src/DeepTensor.cc b/source/api_cc/src/DeepTensor.cc index a9031472e6..a40a16b79c 100644 --- a/source/api_cc/src/DeepTensor.cc +++ b/source/api_cc/src/DeepTensor.cc @@ -6,6 +6,9 @@ #ifdef BUILD_TENSORFLOW #include "DeepTensorTF.h" #endif +#ifdef BUILD_PYTORCH +#include "DeepTensorPT.h" +#endif #include "common.h" using namespace deepmd; @@ -38,7 +41,11 @@ void DeepTensor::init(const std::string &model, throw deepmd::deepmd_exception("TensorFlow backend is not built."); #endif } else if (deepmd::DPBackend::PyTorch == backend) { - throw deepmd::deepmd_exception("PyTorch backend is not supported yet"); +#ifdef BUILD_PYTORCH + dt = std::make_shared(model, gpu_rank, name_scope_); +#else + throw deepmd::deepmd_exception("PyTorch backend is not built."); +#endif } else if (deepmd::DPBackend::Paddle == backend) { throw deepmd::deepmd_exception("PaddlePaddle backend is not supported yet"); } else { diff --git a/source/api_cc/src/DeepTensorPT.cc b/source/api_cc/src/DeepTensorPT.cc new file mode 100644 index 0000000000..2835f829c3 --- /dev/null +++ b/source/api_cc/src/DeepTensorPT.cc @@ -0,0 +1,491 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +#ifdef BUILD_PYTORCH +#include "DeepTensorPT.h" + +#include + +#include +#include // for std::iota +#include + +#include "common.h" +#include "device.h" +#include "errors.h" + +using namespace deepmd; + +static torch::Tensor createNlistTensor( + const std::vector>& data) { + size_t total_size = 0; + for (const auto& row : data) { + total_size += row.size(); + } + std::vector flat_data; + flat_data.reserve(total_size); + for (const auto& row : data) { + flat_data.insert(flat_data.end(), row.begin(), row.end()); + } + + torch::Tensor flat_tensor = torch::tensor(flat_data, torch::kInt32); + int nloc = data.size(); + int nnei = nloc > 0 ? total_size / nloc : 0; + return flat_tensor.view({1, nloc, nnei}); +} + +void DeepTensorPT::translate_error(std::function f) { + try { + f(); + // it seems that libtorch may throw different types of exceptions which are + // inherbited from different base classes + // https://github.com/pytorch/pytorch/blob/13316a8d4642454012d34da0d742f1ba93fc0667/torch/csrc/jit/runtime/interpreter.cpp#L924-L939 + } catch (const c10::Error& e) { + throw deepmd::deepmd_exception("DeePMD-kit PyTorch backend error: " + + std::string(e.what())); + } catch (const torch::jit::JITException& e) { + throw deepmd::deepmd_exception("DeePMD-kit PyTorch backend JIT error: " + + std::string(e.what())); + } catch (const std::runtime_error& e) { + throw deepmd::deepmd_exception("DeePMD-kit PyTorch backend error: " + + std::string(e.what())); + } +} + +DeepTensorPT::DeepTensorPT() : inited(false) {} + +DeepTensorPT::DeepTensorPT(const std::string& model, + const int& gpu_rank, + const std::string& name_scope_) + : inited(false), name_scope(name_scope_) { + try { + translate_error([&] { init(model, gpu_rank, name_scope_); }); + } catch (...) { + // Clean up and rethrow, as the destructor will not be called + throw; + } +} + +void DeepTensorPT::init(const std::string& model, + const int& gpu_rank, + const std::string& name_scope_) { + if (inited) { + std::cerr << "WARNING: deepmd-kit should not be initialized twice, do " + "nothing at the second call of initializer" + << std::endl; + return; + } + name_scope = name_scope_; + deepmd::load_op_library(); + int gpu_num = torch::cuda::device_count(); + if (gpu_num > 0) { + gpu_id = gpu_rank % gpu_num; + } else { + gpu_id = 0; + } + torch::Device device(torch::kCUDA, gpu_id); + gpu_enabled = torch::cuda::is_available(); + if (!gpu_enabled) { + device = torch::Device(torch::kCPU); + std::cout << "load model from: " << model << " to cpu " << std::endl; + } else { +#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM + DPErrcheck(DPSetDevice(gpu_id)); +#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM + std::cout << "load model from: " << model << " to gpu " << gpu_id + << std::endl; + } + std::unordered_map metadata = {{"type", ""}}; + module = torch::jit::load(model, device, metadata); + module.eval(); + + get_env_nthreads(num_intra_nthreads, num_inter_nthreads); + if (num_inter_nthreads) { + try { + at::set_num_interop_threads(num_inter_nthreads); + } catch (...) { + } + } + if (num_intra_nthreads) { + try { + at::set_num_threads(num_intra_nthreads); + } catch (...) { + } + } + + // Get model properties using run_method for C++ interface + auto rcut_result = module.run_method("get_rcut"); + rcut = rcut_result.toDouble(); + + auto ntypes_result = module.run_method("get_ntypes"); + ntypes = ntypes_result.toInt(); + + // Get task dimension from model method + auto task_dim_result = module.run_method("get_task_dim"); + odim = task_dim_result.toInt(); + + // Get type map and set up sel_type + auto type_map_result = module.run_method("get_type_map"); + auto type_map_list = type_map_result.toList(); + sel_type.clear(); + + // For PyTorch models, all types are included (the backend handles exclusions + // internally) The model always outputs all types, but some results may be + // zero + for (size_t i = 0; i < type_map_list.size(); ++i) { + sel_type.push_back(i); + } + inited = true; +} + +DeepTensorPT::~DeepTensorPT() {} + +void DeepTensorPT::get_type_map(std::string& type_map) { + auto type_map_result = module.run_method("get_type_map"); + auto type_map_list = type_map_result.toList(); + type_map.clear(); + for (const torch::IValue& element : type_map_list) { + if (!type_map.empty()) { + type_map += " "; + } + type_map += torch::str(element); + } +} + +template +void DeepTensorPT::compute(std::vector& global_tensor, + std::vector& force, + std::vector& virial, + std::vector& atom_tensor, + std::vector& atom_virial, + const std::vector& coord, + const std::vector& atype, + const std::vector& box, + const bool request_deriv) { + torch::Device device(torch::kCUDA, gpu_id); + if (!gpu_enabled) { + device = torch::Device(torch::kCPU); + } + + int natoms = atype.size(); + auto options = torch::TensorOptions().dtype(torch::kFloat64); + torch::ScalarType floatType = torch::kFloat64; + if (std::is_same::value) { + options = torch::TensorOptions().dtype(torch::kFloat32); + floatType = torch::kFloat32; + } + auto int_options = torch::TensorOptions().dtype(torch::kInt64); + + // Convert inputs to tensors + std::vector coord_wrapped = coord; + at::Tensor coord_tensor = + torch::from_blob(coord_wrapped.data(), {1, natoms, 3}, options) + .to(device); + + std::vector atype_64(atype.begin(), atype.end()); + at::Tensor atype_tensor = + torch::from_blob(atype_64.data(), {1, natoms}, int_options).to(device); + + c10::optional box_tensor; + if (!box.empty()) { + box_tensor = + torch::from_blob(const_cast(box.data()), {1, 9}, options) + .to(device); + } + + // Create input vector + std::vector inputs; + inputs.push_back(coord_tensor); + inputs.push_back(atype_tensor); + inputs.push_back(box_tensor); + + // Add None for fparam and aparam (not used by tensor models) + inputs.push_back(torch::jit::IValue()); // fparam = None + inputs.push_back(torch::jit::IValue()); // aparam = None + inputs.push_back(request_deriv); // do_atomic_virial + + // Forward pass through model + c10::Dict outputs = + module.forward(inputs).toGenericDict(); + + // Extract global dipole/polar results + c10::IValue global_out; + if (outputs.contains("global_dipole")) { + global_out = outputs.at("global_dipole"); + } else if (outputs.contains("global_polar")) { + global_out = outputs.at("global_polar"); + } else { + throw deepmd::deepmd_exception( + "Cannot find global tensor output in model results"); + } + torch::Tensor flat_global_ = global_out.toTensor().view({-1}).to(floatType); + torch::Tensor cpu_global_ = flat_global_.to(torch::kCPU); + global_tensor.assign(cpu_global_.data_ptr(), + cpu_global_.data_ptr() + cpu_global_.numel()); + + // Extract atomic dipole/polar results + c10::IValue atom_out; + if (outputs.contains("dipole")) { + atom_out = outputs.at("dipole"); + } else if (outputs.contains("polar")) { + atom_out = outputs.at("polar"); + } else { + // If no atomic tensor output, create zeros based on global tensor size + int task_dim = global_tensor.size(); + atom_tensor.assign(static_cast(natoms) * task_dim, + static_cast(0.0)); + atom_out = torch::zeros({1, natoms, task_dim}, options); + } + torch::Tensor flat_atom_ = atom_out.toTensor().view({-1}).to(floatType); + torch::Tensor cpu_atom_ = flat_atom_.to(torch::kCPU); + atom_tensor.assign(cpu_atom_.data_ptr(), + cpu_atom_.data_ptr() + cpu_atom_.numel()); + + // Extract force results + c10::IValue force_ = outputs.at("force"); + torch::Tensor flat_force_ = force_.toTensor().view({-1}).to(floatType); + torch::Tensor cpu_force_ = flat_force_.to(torch::kCPU); + force.assign(cpu_force_.data_ptr(), + cpu_force_.data_ptr() + cpu_force_.numel()); + + // Extract virial results + c10::IValue virial_ = outputs.at("virial"); + torch::Tensor flat_virial_ = virial_.toTensor().view({-1}).to(floatType); + torch::Tensor cpu_virial_ = flat_virial_.to(torch::kCPU); + virial.assign(cpu_virial_.data_ptr(), + cpu_virial_.data_ptr() + cpu_virial_.numel()); + // Extract atomic virial results if requested + if (request_deriv) { + c10::IValue atom_virial_ = outputs.at("atom_virial"); + torch::Tensor flat_atom_virial_ = + atom_virial_.toTensor().view({-1}).to(floatType); + torch::Tensor cpu_atom_virial_ = flat_atom_virial_.to(torch::kCPU); + atom_virial.assign( + cpu_atom_virial_.data_ptr(), + cpu_atom_virial_.data_ptr() + cpu_atom_virial_.numel()); + } else { + atom_virial.clear(); + } +} + +template +void DeepTensorPT::compute(std::vector& global_tensor, + std::vector& force, + std::vector& virial, + std::vector& atom_tensor, + std::vector& atom_virial, + const std::vector& coord, + const std::vector& atype, + const std::vector& box, + const int nghost, + const InputNlist& lmp_list, + const bool request_deriv) { + torch::Device device(torch::kCUDA, gpu_id); + if (!gpu_enabled) { + device = torch::Device(torch::kCPU); + } + + int natoms = atype.size(); + auto options = torch::TensorOptions().dtype(torch::kFloat64); + torch::ScalarType floatType = torch::kFloat64; + if (std::is_same::value) { + options = torch::TensorOptions().dtype(torch::kFloat32); + floatType = torch::kFloat32; + } + auto int32_option = + torch::TensorOptions().device(torch::kCPU).dtype(torch::kInt32); + auto int_option = + torch::TensorOptions().device(torch::kCPU).dtype(torch::kInt64); + + // Select real atoms following DeepPotPT pattern + std::vector dcoord, aparam_; + std::vector datype, fwd_map, bkw_map; + int nghost_real, nall_real, nloc_real; + int nall = natoms; + int nframes = 1; + std::vector aparam; // Empty for tensor models + select_real_atoms_coord(dcoord, datype, aparam_, nghost_real, fwd_map, + bkw_map, nall_real, nloc_real, coord, atype, aparam, + nghost, ntypes, nframes, 0, nall, false); + + std::vector coord_wrapped = dcoord; + at::Tensor coord_wrapped_Tensor = + torch::from_blob(coord_wrapped.data(), {1, nall_real, 3}, options) + .to(device); + std::vector atype_64(datype.begin(), datype.end()); + at::Tensor atype_Tensor = + torch::from_blob(atype_64.data(), {1, nall_real}, int_option).to(device); + + // Process neighbor list following DeepPotPT pattern + nlist_data.copy_from_nlist(lmp_list, nall - nghost); + nlist_data.shuffle_exclude_empty(fwd_map); + nlist_data.padding(); + + at::Tensor firstneigh = createNlistTensor(nlist_data.jlist); + firstneigh_tensor = firstneigh.to(torch::kInt64).to(device); + + bool do_atom_virial_tensor = request_deriv; + c10::optional fparam_tensor; + c10::optional aparam_tensor; + c10::optional mapping_tensor; + + // Use forward_lower method following DeepPotPT pattern + c10::Dict outputs = + module + .run_method("forward_lower", coord_wrapped_Tensor, atype_Tensor, + firstneigh_tensor, mapping_tensor, fparam_tensor, + aparam_tensor, do_atom_virial_tensor) + .toGenericDict(); + + // Extract outputs following DeepPotPT pattern + c10::IValue global_dipole_; + if (outputs.contains("global_dipole")) { + global_dipole_ = outputs.at("global_dipole"); + } else if (outputs.contains("global_polar")) { + global_dipole_ = outputs.at("global_polar"); + } else { + throw deepmd::deepmd_exception( + "Cannot find global tensor output in model results"); + } + torch::Tensor flat_global_ = global_dipole_.toTensor().view({-1}); + torch::Tensor cpu_global_ = flat_global_.to(torch::kCPU); + global_tensor.assign(cpu_global_.data_ptr(), + cpu_global_.data_ptr() + cpu_global_.numel()); + + c10::IValue force_ = outputs.at("extended_force"); + torch::Tensor flat_force_ = force_.toTensor().view({-1}).to(floatType); + torch::Tensor cpu_force_ = flat_force_.to(torch::kCPU); + std::vector dforce; + dforce.assign(cpu_force_.data_ptr(), + cpu_force_.data_ptr() + cpu_force_.numel()); + + c10::IValue virial_ = outputs.at("virial"); + torch::Tensor flat_virial_ = virial_.toTensor().view({-1}).to(floatType); + torch::Tensor cpu_virial_ = flat_virial_.to(torch::kCPU); + virial.assign(cpu_virial_.data_ptr(), + cpu_virial_.data_ptr() + cpu_virial_.numel()); + + // bkw map for forces + // Force tensor has shape [nframes, natoms, coord, dipole_components] = [1, 6, + // 3, 3] We need to map it as [nframes, natoms, total_force_components] + int force_components_per_atom = dforce.size() / nall_real; + force.resize(static_cast(nframes) * fwd_map.size() * + force_components_per_atom); + select_map(force, dforce, bkw_map, force_components_per_atom, + nframes, fwd_map.size(), nall_real); + + // Extract atomic dipoles/polars if available + if (outputs.contains("dipole")) { + c10::IValue atom_dipole_ = outputs.at("dipole"); + torch::Tensor flat_atom_dipole_ = + atom_dipole_.toTensor().view({-1}).to(floatType); + torch::Tensor cpu_atom_dipole_ = flat_atom_dipole_.to(torch::kCPU); + std::vector datom_tensor; + datom_tensor.assign( + cpu_atom_dipole_.data_ptr(), + cpu_atom_dipole_.data_ptr() + cpu_atom_dipole_.numel()); + int task_dim = 3; // dipole has 3 components + atom_tensor.resize(static_cast(nframes) * fwd_map.size() * + task_dim); + select_map(atom_tensor, datom_tensor, bkw_map, task_dim, nframes, + fwd_map.size(), nall_real); + } else if (outputs.contains("polar")) { + c10::IValue atom_polar_ = outputs.at("polar"); + torch::Tensor flat_atom_polar_ = + atom_polar_.toTensor().view({-1}).to(floatType); + torch::Tensor cpu_atom_polar_ = flat_atom_polar_.to(torch::kCPU); + std::vector datom_tensor; + datom_tensor.assign( + cpu_atom_polar_.data_ptr(), + cpu_atom_polar_.data_ptr() + cpu_atom_polar_.numel()); + int task_dim = 9; // polarizability has 9 components typically + atom_tensor.resize(static_cast(nframes) * fwd_map.size() * + task_dim); + select_map(atom_tensor, datom_tensor, bkw_map, task_dim, nframes, + fwd_map.size(), nall_real); + } + + if (request_deriv) { + c10::IValue atom_virial_ = outputs.at("extended_virial"); + torch::Tensor flat_atom_virial_ = + atom_virial_.toTensor().view({-1}).to(floatType); + torch::Tensor cpu_atom_virial_ = flat_atom_virial_.to(torch::kCPU); + std::vector datom_virial; + datom_virial.assign( + cpu_atom_virial_.data_ptr(), + cpu_atom_virial_.data_ptr() + cpu_atom_virial_.numel()); + // extended_virial shape is [nframes, natoms, task_dim, 9] so total + // components is task_dim * 9 + int total_virial_components = datom_virial.size() / nall_real; + atom_virial.resize(static_cast(nframes) * fwd_map.size() * + total_virial_components); + select_map(atom_virial, datom_virial, bkw_map, + total_virial_components, nframes, fwd_map.size(), + nall_real); + } +} + +// Public wrapper functions +void DeepTensorPT::computew(std::vector& global_tensor, + std::vector& force, + std::vector& virial, + std::vector& atom_tensor, + std::vector& atom_virial, + const std::vector& coord, + const std::vector& atype, + const std::vector& box, + const bool request_deriv) { + translate_error([&] { + compute(global_tensor, force, virial, atom_tensor, atom_virial, coord, + atype, box, request_deriv); + }); +} + +void DeepTensorPT::computew(std::vector& global_tensor, + std::vector& force, + std::vector& virial, + std::vector& atom_tensor, + std::vector& atom_virial, + const std::vector& coord, + const std::vector& atype, + const std::vector& box, + const bool request_deriv) { + translate_error([&] { + compute(global_tensor, force, virial, atom_tensor, atom_virial, coord, + atype, box, request_deriv); + }); +} + +void DeepTensorPT::computew(std::vector& global_tensor, + std::vector& force, + std::vector& virial, + std::vector& atom_tensor, + std::vector& atom_virial, + const std::vector& coord, + const std::vector& atype, + const std::vector& box, + const int nghost, + const InputNlist& inlist, + const bool request_deriv) { + translate_error([&] { + compute(global_tensor, force, virial, atom_tensor, atom_virial, coord, + atype, box, nghost, inlist, request_deriv); + }); +} + +void DeepTensorPT::computew(std::vector& global_tensor, + std::vector& force, + std::vector& virial, + std::vector& atom_tensor, + std::vector& atom_virial, + const std::vector& coord, + const std::vector& atype, + const std::vector& box, + const int nghost, + const InputNlist& inlist, + const bool request_deriv) { + translate_error([&] { + compute(global_tensor, force, virial, atom_tensor, atom_virial, coord, + atype, box, nghost, inlist, request_deriv); + }); +} + +#endif // BUILD_PYTORCH diff --git a/source/api_cc/tests/test_deeptensor_pt.cc b/source/api_cc/tests/test_deeptensor_pt.cc new file mode 100644 index 0000000000..b323eb8694 --- /dev/null +++ b/source/api_cc/tests/test_deeptensor_pt.cc @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "DeepTensor.h" +#include "neighbor_list.h" +#include "test_utils.h" + +template +class TestInferDeepTensorPt : public ::testing::Test { + protected: + std::vector coord = {12.83, 2.56, 2.18, 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, 4.27, 3.22, 1.56}; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector box = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + + // Expected global tensor values from Python inference + std::vector expected_global_tensor = {0.2338104, 0.23701073, + 0.2334505}; + + // Expected atomic tensor values from Python inference (flattened) + std::vector expected_atom_tensor = {-0.1808925408386811, + 0.3190798607195795, + 0.04760079958216837, + -0.0, + -0.0, + 0.0, + 0.0, + 0.0, + -0.0, + 0.4147029447879755, + -0.08206913353381971, + 0.1858497008385067, + 0.0, + -0.0, + 0.0, + 0.0, + 0.0, + -0.0}; + + int natoms = 6; + int output_dim = 3; + + deepmd::DeepTensor dt; + + void SetUp() override { + std::string file_name = "../../tests/infer/deepdipole_pt.pth"; + dt.init(file_name); + }; + + void TearDown() override {}; +}; + +TYPED_TEST_SUITE(TestInferDeepTensorPt, ValueTypes); + +TYPED_TEST(TestInferDeepTensorPt, cpu_build_nlist) { + using VALUETYPE = TypeParam; + std::vector& coord = this->coord; + std::vector& atype = this->atype; + std::vector& box = this->box; + std::vector& expected_global_tensor = this->expected_global_tensor; + std::vector& expected_atom_tensor = this->expected_atom_tensor; + int& natoms = this->natoms; + int& output_dim = this->output_dim; + deepmd::DeepTensor& dt = this->dt; + // Use reasonable tolerance for minimal trained model + double tensor_tol = 1e-6; + + std::vector global_tensor, force, virial, atom_tensor, atom_virial; + + dt.compute(global_tensor, force, virial, atom_tensor, atom_virial, coord, + atype, box); + + EXPECT_EQ(global_tensor.size(), output_dim); + EXPECT_EQ(atom_tensor.size(), natoms * output_dim); + EXPECT_EQ(force.size(), natoms * output_dim * 3); + EXPECT_EQ(virial.size(), output_dim * 9); + EXPECT_EQ(atom_virial.size(), natoms * output_dim * 9); + + for (int ii = 0; ii < output_dim; ++ii) { + EXPECT_LT(fabs(global_tensor[ii] - expected_global_tensor[ii]), tensor_tol); + } + + for (int ii = 0; ii < natoms * output_dim; ++ii) { + EXPECT_LT(fabs(atom_tensor[ii] - expected_atom_tensor[ii]), tensor_tol); + } +} + +TYPED_TEST(TestInferDeepTensorPt, cpu_build_nlist_auto) { + using VALUETYPE = TypeParam; + std::vector& coord = this->coord; + std::vector& atype = this->atype; + std::vector& box = this->box; + std::vector& expected_global_tensor = this->expected_global_tensor; + std::vector& expected_atom_tensor = this->expected_atom_tensor; + int& natoms = this->natoms; + int& output_dim = this->output_dim; + deepmd::DeepTensor& dt = this->dt; + double ener_tol = 1e-10; + + std::vector global_tensor, force, virial, atom_tensor, atom_virial; + + dt.compute(global_tensor, force, virial, atom_tensor, atom_virial, coord, + atype, box, 0, {}); + + EXPECT_EQ(global_tensor.size(), output_dim); + EXPECT_EQ(atom_tensor.size(), natoms * output_dim); + + for (int ii = 0; ii < output_dim; ++ii) { + EXPECT_LT(fabs(global_tensor[ii] - expected_global_tensor[ii]), ener_tol); + } + + for (int ii = 0; ii < natoms * output_dim; ++ii) { + EXPECT_LT(fabs(atom_tensor[ii] - expected_atom_tensor[ii]), ener_tol); + } +} + +TYPED_TEST(TestInferDeepTensorPt, cpu_lmp_nlist) { + using VALUETYPE = TypeParam; + std::vector& coord = this->coord; + std::vector& atype = this->atype; + std::vector& box = this->box; + std::vector& expected_global_tensor = this->expected_global_tensor; + std::vector& expected_atom_tensor = this->expected_atom_tensor; + int& natoms = this->natoms; + int& output_dim = this->output_dim; + deepmd::DeepTensor& dt = this->dt; + double ener_tol = 1e-10; + + float rc = dt.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, coord, + atype, box, rc); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + std::vector global_tensor, force, virial, atom_tensor, atom_virial; + + dt.compute(global_tensor, force, virial, atom_tensor, atom_virial, coord_cpy, + atype_cpy, box, nall - nloc, inlist); + + EXPECT_EQ(global_tensor.size(), output_dim); + EXPECT_EQ(atom_tensor.size(), natoms * output_dim); + + for (int ii = 0; ii < output_dim; ++ii) { + EXPECT_LT(fabs(global_tensor[ii] - expected_global_tensor[ii]), ener_tol); + } + + for (int ii = 0; ii < natoms * output_dim; ++ii) { + EXPECT_LT(fabs(atom_tensor[ii] - expected_atom_tensor[ii]), ener_tol); + } +} + +TYPED_TEST(TestInferDeepTensorPt, print_summary) { + deepmd::DeepTensor& dt = this->dt; + dt.print_summary(""); +} + +TYPED_TEST(TestInferDeepTensorPt, get_type_map) { + deepmd::DeepTensor& dt = this->dt; + std::string type_map_str; + dt.get_type_map(type_map_str); + // Parse the type map string manually + std::vector type_map; + std::istringstream iss(type_map_str); + std::string token; + while (iss >> token) { + type_map.push_back(token); + } + EXPECT_EQ(type_map.size(), 2); + EXPECT_EQ(type_map[0], "O"); + EXPECT_EQ(type_map[1], "H"); +} + +TYPED_TEST(TestInferDeepTensorPt, get_properties) { + deepmd::DeepTensor& dt = this->dt; + + EXPECT_EQ(dt.numb_types(), 2); + EXPECT_EQ(dt.output_dim(), 3); + EXPECT_DOUBLE_EQ(dt.cutoff(), 4.0); + + std::vector sel_types = dt.sel_types(); + EXPECT_EQ(sel_types.size(), 2); // PyTorch models always return all types + EXPECT_EQ(sel_types[0], 0); // Type 0 (O) + EXPECT_EQ(sel_types[1], + 1); // Type 1 (H) - included but may have zero results +} diff --git a/source/tests/infer/deepdipole_pt.pth b/source/tests/infer/deepdipole_pt.pth new file mode 100644 index 0000000000000000000000000000000000000000..4c93a1b864d60030c864f258155b62aa1fb2862c GIT binary patch literal 127292 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]^qeNgwm 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 literal 0 HcmV?d00001 From f63d5a5f21f47b768a7b20fafb5020b8d9225a97 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 14 Sep 2025 17:32:18 +0800 Subject: [PATCH 2/5] fix tests --- .gitignore | 2 +- ...deeptensor_pt.cc => test_deepdipole_pt.cc} | 29 ------------------- 2 files changed, 1 insertion(+), 30 deletions(-) rename source/api_cc/tests/{test_deeptensor_pt.cc => test_deepdipole_pt.cc} (85%) diff --git a/.gitignore b/.gitignore index 9f63a65219..69f82afbb5 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,7 @@ venv* .vscode/** _build _templates -API_CC +doc/API_CC/ doc/api_py/ doc/api_core/ doc/api_c/ diff --git a/source/api_cc/tests/test_deeptensor_pt.cc b/source/api_cc/tests/test_deepdipole_pt.cc similarity index 85% rename from source/api_cc/tests/test_deeptensor_pt.cc rename to source/api_cc/tests/test_deepdipole_pt.cc index b323eb8694..d19a613584 100644 --- a/source/api_cc/tests/test_deeptensor_pt.cc +++ b/source/api_cc/tests/test_deepdipole_pt.cc @@ -95,35 +95,6 @@ TYPED_TEST(TestInferDeepTensorPt, cpu_build_nlist) { } } -TYPED_TEST(TestInferDeepTensorPt, cpu_build_nlist_auto) { - using VALUETYPE = TypeParam; - std::vector& coord = this->coord; - std::vector& atype = this->atype; - std::vector& box = this->box; - std::vector& expected_global_tensor = this->expected_global_tensor; - std::vector& expected_atom_tensor = this->expected_atom_tensor; - int& natoms = this->natoms; - int& output_dim = this->output_dim; - deepmd::DeepTensor& dt = this->dt; - double ener_tol = 1e-10; - - std::vector global_tensor, force, virial, atom_tensor, atom_virial; - - dt.compute(global_tensor, force, virial, atom_tensor, atom_virial, coord, - atype, box, 0, {}); - - EXPECT_EQ(global_tensor.size(), output_dim); - EXPECT_EQ(atom_tensor.size(), natoms * output_dim); - - for (int ii = 0; ii < output_dim; ++ii) { - EXPECT_LT(fabs(global_tensor[ii] - expected_global_tensor[ii]), ener_tol); - } - - for (int ii = 0; ii < natoms * output_dim; ++ii) { - EXPECT_LT(fabs(atom_tensor[ii] - expected_atom_tensor[ii]), ener_tol); - } -} - TYPED_TEST(TestInferDeepTensorPt, cpu_lmp_nlist) { using VALUETYPE = TypeParam; std::vector& coord = this->coord; From b664dede8bc3327b35d803c2e7b0ea62bde31165 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 14 Sep 2025 18:05:20 +0800 Subject: [PATCH 3/5] fix tests --- source/api_cc/src/DeepTensorPT.cc | 5 ++++- source/api_cc/tests/test_deepdipole_pt.cc | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/source/api_cc/src/DeepTensorPT.cc b/source/api_cc/src/DeepTensorPT.cc index 2835f829c3..081531ed47 100644 --- a/source/api_cc/src/DeepTensorPT.cc +++ b/source/api_cc/src/DeepTensorPT.cc @@ -345,7 +345,10 @@ void DeepTensorPT::compute(std::vector& global_tensor, throw deepmd::deepmd_exception( "Cannot find global tensor output in model results"); } - torch::Tensor flat_global_ = global_dipole_.toTensor().view({-1}); + // in Python, here used double; however, in TF C++, float is used + // for consistency, we use float + torch::Tensor flat_global_ = + global_dipole_.toTensor().view({-1}).to(floatType); torch::Tensor cpu_global_ = flat_global_.to(torch::kCPU); global_tensor.assign(cpu_global_.data_ptr(), cpu_global_.data_ptr() + cpu_global_.numel()); diff --git a/source/api_cc/tests/test_deepdipole_pt.cc b/source/api_cc/tests/test_deepdipole_pt.cc index d19a613584..70e46dd9e9 100644 --- a/source/api_cc/tests/test_deepdipole_pt.cc +++ b/source/api_cc/tests/test_deepdipole_pt.cc @@ -105,7 +105,7 @@ TYPED_TEST(TestInferDeepTensorPt, cpu_lmp_nlist) { int& natoms = this->natoms; int& output_dim = this->output_dim; deepmd::DeepTensor& dt = this->dt; - double ener_tol = 1e-10; + double ener_tol = 1e-6; float rc = dt.cutoff(); int nloc = coord.size() / 3; @@ -126,7 +126,7 @@ TYPED_TEST(TestInferDeepTensorPt, cpu_lmp_nlist) { atype_cpy, box, nall - nloc, inlist); EXPECT_EQ(global_tensor.size(), output_dim); - EXPECT_EQ(atom_tensor.size(), natoms * output_dim); + EXPECT_EQ(atom_tensor.size(), nall * output_dim); for (int ii = 0; ii < output_dim; ++ii) { EXPECT_LT(fabs(global_tensor[ii] - expected_global_tensor[ii]), ener_tol); From f4bd9a2042b6c06842c27b829450cb03566057c7 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 15 Sep 2025 00:13:02 +0800 Subject: [PATCH 4/5] fix `select_map` for force and virial --- source/api_cc/src/DeepTensorPT.cc | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/source/api_cc/src/DeepTensorPT.cc b/source/api_cc/src/DeepTensorPT.cc index 081531ed47..d51db8ecf3 100644 --- a/source/api_cc/src/DeepTensorPT.cc +++ b/source/api_cc/src/DeepTensorPT.cc @@ -367,13 +367,11 @@ void DeepTensorPT::compute(std::vector& global_tensor, cpu_virial_.data_ptr() + cpu_virial_.numel()); // bkw map for forces - // Force tensor has shape [nframes, natoms, coord, dipole_components] = [1, 6, - // 3, 3] We need to map it as [nframes, natoms, total_force_components] - int force_components_per_atom = dforce.size() / nall_real; - force.resize(static_cast(nframes) * fwd_map.size() * - force_components_per_atom); - select_map(force, dforce, bkw_map, force_components_per_atom, - nframes, fwd_map.size(), nall_real); + force.resize(static_cast(nframes) * odim * fwd_map.size() * 3); + for (int kk = 0; kk < odim; ++kk) { + select_map(force.begin() + kk * fwd_map.size() * 3, + dforce.begin() + kk * bkw_map.size() * 3, bkw_map, 3); + } // Extract atomic dipoles/polars if available if (outputs.contains("dipole")) { @@ -415,14 +413,13 @@ void DeepTensorPT::compute(std::vector& global_tensor, datom_virial.assign( cpu_atom_virial_.data_ptr(), cpu_atom_virial_.data_ptr() + cpu_atom_virial_.numel()); - // extended_virial shape is [nframes, natoms, task_dim, 9] so total - // components is task_dim * 9 - int total_virial_components = datom_virial.size() / nall_real; - atom_virial.resize(static_cast(nframes) * fwd_map.size() * - total_virial_components); - select_map(atom_virial, datom_virial, bkw_map, - total_virial_components, nframes, fwd_map.size(), - nall_real); + atom_virial.resize(static_cast(nframes) * odim * fwd_map.size() * + 9); + for (int kk = 0; kk < odim; ++kk) { + select_map(atom_virial.begin() + kk * fwd_map.size() * 9, + datom_virial.begin() + kk * bkw_map.size() * 9, + bkw_map, 9); + } } } From 9e0a0b6baa60da25269f9bac5db1edf0fcc4501f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 06:29:32 +0000 Subject: [PATCH 5/5] Addressing PR comments Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> --- source/api_cc/include/DeepTensorPT.h | 13 ------- source/api_cc/src/DeepTensorPT.cc | 53 ++++++++++++---------------- 2 files changed, 22 insertions(+), 44 deletions(-) diff --git a/source/api_cc/include/DeepTensorPT.h b/source/api_cc/include/DeepTensorPT.h index 43a104c6af..c602fc53e0 100644 --- a/source/api_cc/include/DeepTensorPT.h +++ b/source/api_cc/include/DeepTensorPT.h @@ -121,19 +121,6 @@ class DeepTensorPT : public DeepTensorBase { **/ int output_dim() const { assert(inited); - if (odim == -1) { - // Check if model has get_task_dim method by trying to call it - try { - auto task_dim_result = module.run_method("get_task_dim"); - odim = task_dim_result.toInt(); - } catch (const std::exception&) { - throw deepmd::deepmd_exception( - "PyTorch tensor model does not implement get_task_dim() method. " - "Please re-freeze the model with DeePMD-kit v3.2 or above that " - "includes this " - "method."); - } - } return odim; }; /** diff --git a/source/api_cc/src/DeepTensorPT.cc b/source/api_cc/src/DeepTensorPT.cc index d51db8ecf3..1636f3af95 100644 --- a/source/api_cc/src/DeepTensorPT.cc +++ b/source/api_cc/src/DeepTensorPT.cc @@ -228,11 +228,8 @@ void DeepTensorPT::compute(std::vector& global_tensor, } else if (outputs.contains("polar")) { atom_out = outputs.at("polar"); } else { - // If no atomic tensor output, create zeros based on global tensor size - int task_dim = global_tensor.size(); - atom_tensor.assign(static_cast(natoms) * task_dim, - static_cast(0.0)); - atom_out = torch::zeros({1, natoms, task_dim}, options); + throw deepmd::deepmd_exception( + "Cannot find atomic tensor output in model results"); } torch::Tensor flat_atom_ = atom_out.toTensor().view({-1}).to(floatType); torch::Tensor cpu_atom_ = flat_atom_.to(torch::kCPU); @@ -374,36 +371,30 @@ void DeepTensorPT::compute(std::vector& global_tensor, } // Extract atomic dipoles/polars if available + c10::IValue atom_tensor_output; + int task_dim; if (outputs.contains("dipole")) { - c10::IValue atom_dipole_ = outputs.at("dipole"); - torch::Tensor flat_atom_dipole_ = - atom_dipole_.toTensor().view({-1}).to(floatType); - torch::Tensor cpu_atom_dipole_ = flat_atom_dipole_.to(torch::kCPU); - std::vector datom_tensor; - datom_tensor.assign( - cpu_atom_dipole_.data_ptr(), - cpu_atom_dipole_.data_ptr() + cpu_atom_dipole_.numel()); - int task_dim = 3; // dipole has 3 components - atom_tensor.resize(static_cast(nframes) * fwd_map.size() * - task_dim); - select_map(atom_tensor, datom_tensor, bkw_map, task_dim, nframes, - fwd_map.size(), nall_real); + atom_tensor_output = outputs.at("dipole"); + task_dim = 3; // dipole has 3 components } else if (outputs.contains("polar")) { - c10::IValue atom_polar_ = outputs.at("polar"); - torch::Tensor flat_atom_polar_ = - atom_polar_.toTensor().view({-1}).to(floatType); - torch::Tensor cpu_atom_polar_ = flat_atom_polar_.to(torch::kCPU); - std::vector datom_tensor; - datom_tensor.assign( - cpu_atom_polar_.data_ptr(), - cpu_atom_polar_.data_ptr() + cpu_atom_polar_.numel()); - int task_dim = 9; // polarizability has 9 components typically - atom_tensor.resize(static_cast(nframes) * fwd_map.size() * - task_dim); - select_map(atom_tensor, datom_tensor, bkw_map, task_dim, nframes, - fwd_map.size(), nall_real); + atom_tensor_output = outputs.at("polar"); + task_dim = 9; // polarizability has 9 components typically + } else { + throw deepmd::deepmd_exception( + "Cannot find atomic tensor output in model results"); } + torch::Tensor flat_atom_tensor_ = + atom_tensor_output.toTensor().view({-1}).to(floatType); + torch::Tensor cpu_atom_tensor_ = flat_atom_tensor_.to(torch::kCPU); + std::vector datom_tensor; + datom_tensor.assign( + cpu_atom_tensor_.data_ptr(), + cpu_atom_tensor_.data_ptr() + cpu_atom_tensor_.numel()); + atom_tensor.resize(static_cast(nframes) * fwd_map.size() * task_dim); + select_map(atom_tensor, datom_tensor, bkw_map, task_dim, nframes, + fwd_map.size(), nall_real); + if (request_deriv) { c10::IValue atom_virial_ = outputs.at("extended_virial"); torch::Tensor flat_atom_virial_ =