Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tf/pt): add/refact lammps support for spin model #4216

Closed
wants to merge 59 commits into from

Conversation

iProzd
Copy link
Collaborator

@iProzd iProzd commented Oct 15, 2024

Summary by CodeRabbit

  • New Features

    • Introduced spin handling capabilities in various models, enhancing energy and force computations.
    • Added support for new parameters in compute methods to accommodate ghost atoms and neighbor lists.
    • Implemented new classes and methods for managing spin interactions, including DeepSpin, DeepSpinModelDevi, and their TensorFlow and PyTorch counterparts.
    • Added a new pair style for LAMMPS simulations: PairDeepSpin.
    • Enhanced the DeepPot framework with spin support, including new API structures and functions.
    • Introduced a new function for writing LAMMPS data that includes spin information.
    • Added comprehensive functionality for error handling and tensor management in DeepSpinPT and DeepSpinTF.
    • Established a new testing framework for the DeepSpin class to validate its methods under various configurations.
  • Bug Fixes

    • Improved error handling in TensorFlow and PyTorch integrations to ensure robustness during model execution.
  • Tests

    • Established comprehensive unit tests for the DeepSpin class, validating spin-related computations and ensuring accuracy in energy and force calculations.
    • Introduced additional tests for the DeepSpin class, focusing on the compute method and verifying outputs against expected values.
    • Added unit tests for the DeepSpinPT class to validate its functionality.
    • Enhanced testing framework for LAMMPS spin simulations, ensuring correctness across various scenarios.
    • Developed tests for the DeepSpin class to validate its behavior with and without periodic boundary conditions.
  • Documentation

    • Enhanced documentation for new methods and classes to clarify usage and functionality related to spin interactions.

@iProzd iProzd marked this pull request as draft October 15, 2024 16:00
Copy link
Contributor

coderabbitai bot commented Oct 15, 2024

Warning

Rate limit exceeded

@iProzd has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 24 minutes and 53 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between a532c33 and ab15e47.

📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough

Walkthrough

The pull request introduces significant enhancements across multiple components of the DeepMD framework, focusing on the integration of spin functionality. Key modifications include the addition of optional parameters for spin handling in various methods of the SpinModel, SpinEnergyModel, and DeepPotPT classes. New classes like DeepSpin and DeepSpinPT are introduced to manage spin interactions, while existing classes are updated for better handling of parameters related to spin. The changes also include new testing frameworks to validate the functionality of these enhancements.

Changes

File Path Change Summary
deepmd/pt/model/model/spin_model.py Added comm_dict parameter to forward_common_lower methods in SpinModel and SpinEnergyModel. Removed concat_switch_virtual method.
source/api_cc/src/DeepPotPT.cc Added overloads for compute and computew methods with new parameters. Introduced computew_mixed_type method.
source/api_cc/include/DeepPotPT.h Updated compute and computew method signatures to include force_mag and spin parameters.
deepmd/pt/model/descriptor/repformers.py Enhanced forward method in DescrptBlockRepformers to handle spin states.
deepmd/pt/utils/spin.py Introduced concat_switch_virtual function for tensor concatenation.
deepmd/tf/entrypoints/freeze.py Updated node management for freezing TensorFlow graphs to include new spin-related nodes.
source/api_cc/src/DeepPotTF.cc Added new methods for vector retrieval and cumulative sum. Updated computew methods to handle new parameters.
source/api_c/include/c_api.h Introduced new structures and functions for deep potential models with spin.
source/api_c/include/deepmd.hpp Added methods for spin support in DeepPot and DeepPotModelDevi classes.
source/api_c/src/c_api.cc Added support for spin functionality in various computational models.
source/api_cc/include/DeepBaseModel.h Introduced DeepBaseModel and DeepBaseModelDevi classes for managing deep potential models.
source/api_cc/include/DeepSpin.h Added DeepSpinBase and DeepSpin classes for handling spin interactions.
source/api_cc/src/DeepSpin.cc Implemented DeepSpin and DeepSpinModelDevi classes for managing spin dynamics.
source/api_cc/src/DeepSpinPT.cc Introduced DeepSpinPT class for PyTorch integration with spin handling.
source/api_cc/src/DeepSpinTF.cc Added DeepSpinTF class for TensorFlow integration with spin handling.
source/api_cc/tests/test_deeppot_tf_spin.cc Created unit tests for the DeepSpin class using Google Test framework.
source/lmp/pair_deepmd.cpp Removed spin-related functionality from PairDeepMD class.
source/lmp/pair_deepmd.h Updated PairDeepMD class to inherit from PairDeepMDBase, removing spin-related methods.
source/lmp/pair_deepspin.cpp Implemented PairDeepSpin class for handling spin atoms in LAMMPS simulations.
source/lmp/pair_deepspin.h Defined PairDeepSpin class with methods for settings and computation.
source/lmp/tests/run_mpi_pair_deepmd_spin.py Script for executing LAMMPS simulation with spin interactions using MPI.
source/lmp/tests/test_lammps_spin.py Comprehensive testing suite for LAMMPS spin interactions.
source/lmp/tests/test_lammps_spin_pt.py Enhanced unit testing framework for spin interactions in LAMMPS.
source/lmp/tests/write_lmp_data.py Added write_lmp_data_spin function for writing LMP data with spin information.
source/lmp/plugin/deepmdplugin.cpp Registered new pair style plugin for "deepspin".
source/install/build_lammps.sh Updated build script to include PKG_SPIN during CMake configuration.
source/api_c/include/c_api_internal.h Introduced new structures for deep learning models with spin.
source/api_c/tests/test_deeppot_a.cc Updated tests to utilize new base model interface for DP_DeepPot.
source/api_cc/src/DeepBaseModel.cc Implemented methods for DeepBaseModel and DeepBaseModelDevi classes.
source/api_cc/src/DeepSpinPT.cc Implemented methods for DeepSpinPT class, integrating with PyTorch.
source/api_cc/src/DeepSpinTF.cc Implemented methods for DeepSpinTF class, integrating with TensorFlow.
source/api_cc/tests/test_deeppot_dpa_pt_spin.cc Created unit tests for the DeepSpin class with Google Test framework.

Possibly related PRs

Suggested labels

OP

Suggested reviewers

  • iProzd
  • wanghan-iapcm

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Comment on lines 378 to 379
// std::vector<double> virtual_len;
// std::vector<double> spin_norm;

Check notice

Code scanning / CodeQL

Commented-out code

This comment appears to contain commented-out code.
std::vector<int> extend_numneigh;
std::vector<std::vector<int>> extend_neigh;
std::vector<int*> extend_firstneigh;
// std::vector<double> extend_dcoord;

Check notice

Code scanning / CodeQL

Commented-out code

This comment appears to contain commented-out code.
select_real_atoms_coord(dcoord, datype, aparam_, nghost_real, fwd_map,
bkw_map, nall_real, nloc_real, coord, atype, aparam,
nghost, ntypes, 1, daparam, nall, aparam_nall);
int nloc = nall_real - nghost_real;

Check notice

Code scanning / CodeQL

Unused local variable

Variable nloc is not used.
Comment on lines 462 to 466
// spin model not suported yet
// 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<VALUETYPE>(),
// cpu_virial_.data_ptr<VALUETYPE>() + cpu_virial_.numel());

Check notice

Code scanning / CodeQL

Commented-out code

This comment appears to contain commented-out code.
// cpu_atom_virial_.data_ptr<VALUETYPE>(),
// cpu_atom_virial_.data_ptr<VALUETYPE>() + cpu_atom_virial_.numel());
atom_energy.resize(static_cast<size_t>(nframes) * fwd_map.size());
// atom_virial.resize(static_cast<size_t>(nframes) * fwd_map.size() * 9);

Check notice

Code scanning / CodeQL

Commented-out code

This comment appears to contain commented-out code.
Comment on lines 748 to 752
// spin model not suported yet
// 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<VALUETYPE>(),
// cpu_virial_.data_ptr<VALUETYPE>() + cpu_virial_.numel());

Check notice

Code scanning / CodeQL

Commented-out code

This comment appears to contain commented-out code.
// virial.assign(cpu_virial_.data_ptr<VALUETYPE>(),
// cpu_virial_.data_ptr<VALUETYPE>() + cpu_virial_.numel());
if (atomic) {
// c10::IValue atom_virial_ = outputs.at("atom_virial");

Check notice

Code scanning / CodeQL

Commented-out code

This comment appears to contain commented-out code.
}

if (dtype == tensorflow::DT_DOUBLE) {
int ret = session_input_tensors<double>(

Check notice

Code scanning / CodeQL

Unused local variable

Variable ret is not used.
nframes, nghost_real);
}
} else {
int ret = session_input_tensors<float>(

Check notice

Code scanning / CodeQL

Unused local variable

Variable ret is not used.
@@ -1198,7 +1245,12 @@ void PairDeepMD::settings(int narg, char **arg) {
}
}

comm_reverse = numb_models * 3;
// comm_reverse = numb_models * 3;

Check notice

Code scanning / CodeQL

Commented-out code

This comment appears to contain commented-out code.
std::vector<int> extend_numneigh;
std::vector<std::vector<int>> extend_neigh;
std::vector<int*> extend_firstneigh;
// std::vector<double> extend_dcoord;

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.
@@ -1198,7 +1245,12 @@
}
}

comm_reverse = numb_models * 3;
// comm_reverse = numb_models * 3;

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 34

🧹 Outside diff range and nitpick comments (13)
deepmd/tf/entrypoints/freeze.py (2)

264-265: LGTM! Consider grouping related optional nodes.

The addition of spin_attr/virtual_len and spin_attr/spin_norm to the optional_node list is a good practice. It ensures backward compatibility with models that don't have spin attributes.

For improved readability, consider grouping related optional nodes together. You could refactor the optional_node list as follows:

optional_node = [
    "train_attr/min_nbor_dist",
    "fitting_attr/aparam_nall",
    # Spin-related attributes
    "spin_attr/ntypes_spin",
    "spin_attr/virtual_len",
    "spin_attr/spin_norm",
]

This grouping makes it easier to identify and manage related optional nodes.


Line range hint 1-389: Overall changes look good. Consider updating documentation.

The changes to add support for spin-related computations in the freezing process are well-implemented and consistent with the PR objectives. The modifications are minimal and targeted, which is a good practice for reducing the risk of introducing bugs.

To ensure that users and developers are aware of the new spin-related functionality, consider updating the module or function docstrings to mention the new spin attributes. For example, you could add a note to the freeze_graph function docstring:

def freeze_graph(...):
    """Freeze the single graph with chosen out_suffix.

    ...

    Notes
    -----
    This function now supports freezing of spin-related attributes
    (virtual_len and spin_norm) for the "ener" model type.
    """
    ...

This documentation update will help users understand the new capabilities added by these changes.

deepmd/pt/model/model/spin_model.py (2)

Line range hint 474-497: LGTM! Consider adding documentation for new parameters.

The addition of comm_dict and extra_nlist_sort parameters enhances the flexibility of the forward_common_lower method. However, it would be beneficial to document their purpose and usage in the method's docstring.

Consider adding documentation for the new parameters:

def forward_common_lower(
    self,
    extended_coord,
    extended_atype,
    extended_spin,
    nlist,
    mapping: Optional[torch.Tensor] = None,
    fparam: Optional[torch.Tensor] = None,
    aparam: Optional[torch.Tensor] = None,
    do_atomic_virial: bool = False,
    comm_dict: Optional[Dict[str, torch.Tensor]] = None,
    extra_nlist_sort: bool = False,
):
    """
    ...
    Parameters:
    ...
    comm_dict: Optional dictionary for additional communication data.
    extra_nlist_sort: Boolean flag for additional neighbor list sorting.
    ...
    """

Line range hint 612-624: LGTM! Consider adding documentation for the new parameter.

The addition of the comm_dict parameter and its usage are consistent with the changes in the parent class. The extra_nlist_sort parameter is now properly utilized.

Consider adding documentation for the new parameter:

@torch.jit.export
def forward_lower(
    self,
    extended_coord,
    extended_atype,
    extended_spin,
    nlist,
    mapping: Optional[torch.Tensor] = None,
    fparam: Optional[torch.Tensor] = None,
    aparam: Optional[torch.Tensor] = None,
    do_atomic_virial: bool = False,
    comm_dict: Optional[Dict[str, torch.Tensor]] = None,
):
    """
    ...
    Parameters:
    ...
    comm_dict: Optional dictionary for additional communication data.
    ...
    """
source/api_cc/include/DeepPotTF.h (5)

118-134: Add documentation for the new compute method overload

The newly added compute method overload at lines 118-134 introduces additional parameters force_mag and spin. To maintain code clarity and assist users, please add accompanying documentation that describes the purpose of this method and explains each parameter.


282-313: Add documentation for the new computew method overloads

The overloaded computew methods at lines 282-313 include new parameters force_mag and spin. To maintain consistency and aid users, please provide detailed documentation for these methods, explaining the purpose of the new parameters and any changes in the method's behavior.


359-359: Provide parameter names in the cum_sum method declaration

At line 359, the cum_sum method is declared without parameter names:

void cum_sum(std::map<int, int>&, std::map<int, int>&);

For better code readability and maintainability, please include descriptive parameter names:

void cum_sum(std::map<int, int>& input_map, std::map<int, int>& output_map);

378-379: Remove or clarify commented-out code

The lines 378-379 contain commented-out declarations:

// std::vector<double> virtual_len;
// std::vector<double> spin_norm;

If these variables are no longer needed, please remove them to keep the code clean. If they are intended for future use, add comments explaining their purpose.


131-131: Pass small integers by value instead of const reference

In the method parameters at lines 131, 294, and 310, the integer ago is passed as const int& ago. Since int is a small built-in type, passing it by value is more efficient and avoids the overhead of referencing. Please consider changing the parameter to:

const int ago

Also applies to: 294-294, 310-310

source/api_cc/src/DeepPotPT.cc (2)

446-447: Typo in comment: 'suported' should be 'supported'

There's a typographical error in the comment on line 446. Correct the spelling of "suported" to "supported" for clarity.

Apply this diff to fix the typo:

-// spin model not suported yet
+// Spin model not supported yet

463-466: Remove unnecessary commented-out code

The block of commented-out code related to virial_ is unnecessary since it's already indicated that the spin model does not support virial calculations yet. Removing this block can improve code readability.

Apply this diff to remove the unnecessary code:

-// 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<VALUETYPE>(),
-//               cpu_virial_.data_ptr<VALUETYPE>() + cpu_virial_.numel());
source/lmp/pair_deepmd.cpp (1)

1249-1253: Clarify the computation of comm_reverse

You conditionally set comm_reverse based on atom->sp_flag:

if (atom->sp_flag) {
  comm_reverse = numb_models * 3 * 2;
} else {
  comm_reverse = numb_models * 3;
}

Consider adding comments or refactoring for clarity to indicate why the factor is * 2 when atom->sp_flag is true. This will enhance maintainability and readability.

source/api_c/include/c_api.h (1)

233-247: Add documentation for the new API function

The function DP_DeepPotComputeNListSP lacks a documentation comment block. Please add a documentation block similar to other functions, describing the purpose, parameters, and any important notes.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6fe8dde and 3466e34.

📒 Files selected for processing (13)
  • deepmd/pt/model/model/spin_model.py (4 hunks)
  • deepmd/tf/entrypoints/freeze.py (2 hunks)
  • source/api_c/include/c_api.h (8 hunks)
  • source/api_c/include/deepmd.hpp (6 hunks)
  • source/api_c/src/c_api.cc (10 hunks)
  • source/api_cc/include/DeepPot.h (5 hunks)
  • source/api_cc/include/DeepPotPT.h (4 hunks)
  • source/api_cc/include/DeepPotTF.h (3 hunks)
  • source/api_cc/src/DeepPot.cc (4 hunks)
  • source/api_cc/src/DeepPotPT.cc (4 hunks)
  • source/api_cc/src/DeepPotTF.cc (4 hunks)
  • source/lmp/pair_deepmd.cpp (15 hunks)
  • source/lmp/pair_deepmd.h (1 hunks)
🧰 Additional context used
🔇 Additional comments (41)
deepmd/tf/entrypoints/freeze.py (1)

127-128: LGTM! Verify impact on other parts of the codebase.

The addition of spin_attr/virtual_len and spin_attr/spin_norm nodes for the "ener" model type is consistent with the PR objectives to add support for spin models. This change looks good and should enable the freezing of spin-related attributes.

To ensure these changes don't have unintended consequences, please run the following script to check for any other occurrences of these new attributes in the codebase:

This will help verify that these new attributes are consistently used across the project.

✅ Verification successful

Verified! No unintended occurrences of new spin attributes found elsewhere.

The newly added spin_attr/virtual_len and spin_attr/spin_norm nodes are exclusively present in deepmd/tf/entrypoints/freeze.py. Their implementation is confined to this file, ensuring that there are no unintended side effects in other parts of the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for other occurrences of new spin attributes

echo "Searching for 'spin_attr/virtual_len':"
rg "spin_attr/virtual_len" --type py

echo "\nSearching for 'spin_attr/spin_norm':"
rg "spin_attr/spin_norm" --type py

Length of output: 521

deepmd/pt/model/model/spin_model.py (1)

Line range hint 1-638: Overall, the changes look good and enhance the model's flexibility.

The additions of comm_dict and extra_nlist_sort parameters in both SpinModel and SpinEnergyModel classes are well-implemented and consistent. These changes provide more flexibility in the forward pass and neighbor list sorting. The code maintains good quality and there are no apparent issues introduced by these changes.

To further improve the code:

  1. Consider adding documentation for the new parameters in both forward_common_lower and forward_lower methods.
  2. Ensure that the usage of comm_dict is properly documented in the broader context of the DeepMD framework, explaining when and how it should be used.
source/lmp/pair_deepmd.h (1)

78-78: LGTM!

The addition of all_force_mag as a member variable appears appropriate.

source/api_cc/include/DeepPotTF.h (3)

126-126: Confirm the correctness of spin data type

At line 126, spin is declared as const std::vector<VALUETYPE>& spin. Since spin values might be integers in some models, ensure that VALUETYPE is the appropriate data type for representing spins in all cases. If spins are always floating-point numbers, this is acceptable; otherwise, consider using a more suitable type.


289-289: Consistent data types for spin across methods

In the computew methods, spin is declared as const std::vector<double>& at line 289 and const std::vector<float>& at line 305. Ensure that the usage of double and float for spin aligns with the rest of the method parameters and that any casting or precision considerations are properly handled.

Also applies to: 305-305


368-370: Check for duplication of get_vector method

The get_vector template method is declared at lines 368-370. Ensure that this declaration does not duplicate an existing method and that it is necessary for the extended functionality. If it's an intentional addition, consider providing documentation to explain its purpose.

source/api_cc/include/DeepPotPT.h (1)

77-90: Verify consistency of parameter ordering across method overloads

Ensure that the ordering of parameters, particularly the placement of spin and force_mag, is consistent with existing methods and logical grouping. Consistent parameter ordering prevents confusion and potential bugs.

source/api_cc/src/DeepPotPT.cc (5)

658-798: Consistent handling of optional tensors

Ensure that optional tensors like box_Tensor, fparam_tensor, and aparam_tensor are consistently handled across different compute methods. This prevents unexpected behaviors when these optional parameters are absent.

Please verify that all optional tensors are checked for validity before use to avoid null pointer dereferences.


Line range hint 446-793: Correct inconsistency in handling do_message_passing and nghost

Throughout the new compute methods, ensure that the conditional checks for do_message_passing and nghost are consistent and correctly implemented. This is crucial for parallel computations and message passing between processes.

Review the conditional logic to confirm that all possible states of do_message_passing and nghost are appropriately handled.


755-767: Commented-out code may indicate incomplete implementation

The commented-out sections related to atom_virial_ suggest that the spin model's support for atomic virials is incomplete.

Confirm whether the implementation of atomic virials with the spin model is pending. If so, consider adding a TODO comment to track this for future development.


468-474: ⚠️ Potential issue

Initialize force_mag vector before use

The force_mag vector should be initialized appropriately before being used in the select_map function to avoid potential undefined behavior.

Apply this diff to ensure force_mag is correctly initialized:

 force.resize(static_cast<size_t>(nframes) * fwd_map.size() * 3);
+force_mag.resize(static_cast<size_t>(nframes) * fwd_map.size() * 3);
 select_map<VALUETYPE>(force, dforce, bkw_map, 3, nframes, fwd_map.size(),
                       nall_real);
 select_map<VALUETYPE>(force_mag, dforce_mag, bkw_map, 3, nframes,
                       fwd_map.size(), nall_real);

Likely invalid or redundant comment.


503-535: Ensure explicit instantiation of template methods for required types

The explicit template instantiations at the end of the file should cover all the necessary data type combinations used in the codebase. Verify that the methods are instantiated for all required VALUETYPE and ENERGYVTYPE combinations.

Run the following script to check for all instantiations:

Ensure that the output includes all necessary type combinations.

Also applies to: 772-798

✅ Verification successful

All required VALUETYPE and ENERGYVTYPE combinations are explicitly instantiated.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for explicit template instantiations of compute methods.

# Search for lines with 'template void DeepPotPT::compute<'
rg --type cpp 'template void DeepPotPT::compute<' -A 2

Length of output: 1885


Script:

#!/bin/bash
# Description: Identify all unique VALUETYPEs used in DeepPotPT::compute method calls.

# Extract all compute method calls and capture the VALUETYPE template argument
rg --type cpp 'DeepPotPT::compute<' | \
    sed -n "s/.*DeepPotPT::compute<\([^,>]*\),.*/\1/p" | \
    sort | uniq

Length of output: 117

source/lmp/pair_deepmd.cpp (6)

582-586: Verify the updated deep_pot.compute method signature

The deep_pot.compute function is called with additional parameters dforce_mag and dspin_const. Ensure that the deep_pot.compute method signature has been updated accordingly and all dependencies are properly handled.


606-608: Ensure consistency in deep_pot.compute calls with spin parameters

When calling deep_pot.compute, you are passing dspin. Verify that this parameter is correctly handled within the function and that all spin-related computations are accurate.


1407-1423: Ensure correct packing of reverse communication buffer with spin data

In pack_reverse_comm, you have added code to handle spin data:

if (atom->sp_flag) {
  // Code handling spin data
} else {
  // Original code
}

Verify that the buffer buf is being correctly populated, and that the size calculations match the expected data to prevent communication errors.


1436-1454: Validate unpacking of reverse communication buffer with spin data

Similar to packing, in unpack_reverse_comm, ensure that the unpacking logic correctly aligns with the packing structure, particularly with the added spin data. Mismatches here can lead to incorrect force calculations.


771-783: Check calculations for spin-related force deviations

In the block handling spin forces:

if (atom->sp_flag) {
  // Calculations for std_fm, tmp_avg_fm, etc.
}

Verify that the statistical calculations for std_fm, all_fm_min, all_fm_max, and all_fm_avg are accurate and that they properly represent the deviations intended.


657-693: ⚠️ Potential issue

Handle possible issues with model deviation calculations

In the multi-model deviation computation block, there are nested conditionals and numerous variables like all_force_mag, all_force, all_energy, etc. Ensure that:

  • All vectors are properly initialized before use.
  • The indexing aligns correctly across different models.
  • Memory management is correctly handled to prevent leaks.
source/api_cc/src/DeepPotTF.cc (1)

1429-1441: Check for potential out-of-bounds access in extend_atype assignment

In the loop updating extend_atype, there is a risk of out-of-bounds access when calculating indices with new_idx_map[ii] + nloc and new_idx_map[ii] + nghost. Ensure that these calculated indices do not exceed the size of extend_atype.

Run the following script to check index bounds:

Ensure that extend_atype is appropriately sized to accommodate these indices or adjust the index calculations to prevent out-of-bounds access.

source/api_cc/src/DeepPot.cc (6)

221-242: Correct implementation of spin support in DeepPot::compute method

The new overload of the compute method correctly includes the spin parameters dspin_ and dforce_mag_. The parameters are appropriately passed to dp->computew, ensuring that spin calculations are integrated seamlessly.


244-262: Proper extension of compute method for vector energies with spin

The overloaded compute method that returns vector energies now includes dspin_ and dforce_mag_ parameters. The adjustments ensure that spin data is consistently handled across computations.


264-319: Accurate template instantiations for spin-inclusive compute methods

The explicit template instantiations for both double and float types are correctly provided for the new compute methods with spin support. This ensures type safety and availability of these methods for different numerical precisions.


488-596: Extension of compute methods with atomic outputs and spin support

The compute methods that include atomic energies and virials have been appropriately extended to incorporate spin parameters. The modifications correctly pass dspin_ and dforce_mag_ to dp->computew, enabling detailed spin-aware computations at the atomic level.


954-1012: Integration of spin support in DeepPotModelDevi::compute method

The DeepPotModelDevi::compute method now includes support for spin parameters, adding dspin_ and dforce_mag_ to the computation of energies, forces, and virials across multiple models. The loop over numb_models ensures consistent processing of spin data.


1073-1140: Enhanced compute method with spin and atomic outputs in DeepPotModelDevi

The overloaded compute method in DeepPotModelDevi has been correctly expanded to handle spin parameters and compute atomic energies and virials. This comprehensive extension ensures that all relevant spin-related data is accurately calculated for each model.

source/api_c/include/c_api.h (6)

287-302: Add documentation for the new API function

Please add a documentation block for DP_DeepPotComputeNListfSP to maintain consistency with other functions in the API.


427-445: Add documentation for the new API function

Please add a documentation block for DP_DeepPotComputeNList2SP to maintain consistency with other functions.


492-510: Add documentation for the new API function

Please add a documentation block for DP_DeepPotComputeNListf2SP to maintain consistency.


807-822: Add documentation for the new API function

Please add a documentation block for DP_DeepPotModelDeviComputeNListSP similar to other functions in the API.


860-875: Add documentation for the new API function

Please add a documentation block for DP_DeepPotModelDeviComputeNListfSP to maintain consistency.


987-1005: Add 'extern' keyword to function declaration

The function DP_DeepPotModelDeviComputeNListf2SP lacks the extern keyword in its declaration. Please add extern to maintain consistency.

Here is the suggested change:

-void DP_DeepPotModelDeviComputeNListf2SP(DP_DeepPotModelDevi* dp,
+extern void DP_DeepPotModelDeviComputeNListf2SP(DP_DeepPotModelDevi* dp,
source/api_c/src/c_api.cc (10)

419-454: LGTM!

The template instantiations for the new DP_DeepPotComputeNList_variant_sp function look good.


1304-1322: LGTM!

The new DP_DeepPotComputeNListfSP function for the float type looks good.


1382-1403: LGTM!

The new DP_DeepPotComputeNList2SP function for handling multiple frames with spin looks good.


1426-1447: LGTM!

The new DP_DeepPotComputeNListf2SP function for the float type with multiple frames looks good.


1595-1613: LGTM!

The new DP_DeepPotModelDeviComputeNListSP function for the model deviation with spin looks good.


1633-1651: LGTM!

The new DP_DeepPotModelDeviComputeNListfSP function for the float type model deviation with spin looks good.


1674-1695: LGTM!

The new DP_DeepPotModelDeviComputeNList2SP function for handling multiple frames in the model deviation with spin looks good.


1718-1739: LGTM!

The new DP_DeepPotModelDeviComputeNListf2SP function for the float type model deviation with multiple frames and spin looks good.


842-879: LGTM!

The template instantiations for the new DP_DeepPotModelDeviComputeNList_variant_sp function look good.


1266-1284: Verify the new function is called correctly from all relevant code paths.

The new DP_DeepPotComputeNListSP function looks good. However, ensure it is being called correctly from all the relevant code paths that need to compute energy, force, force_mag, virial, etc. with spin.

Run the following script to verify the function usage:

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 35

🧹 Outside diff range and nitpick comments (23)
deepmd/tf/entrypoints/freeze.py (1)

264-265: LGTM. Consider grouping related attributes.

The addition of "spin_attr/virtual_len" and "spin_attr/spin_norm" to the optional node list is consistent with the earlier changes and provides flexibility in the freezing process.

For improved readability, consider grouping related attributes together. You could move the "spin_attr/ntypes_spin" node (currently on line 263) next to the newly added spin attributes:

optional_node = [
    "train_attr/min_nbor_dist",
    "fitting_attr/aparam_nall",
    "spin_attr/ntypes_spin",
    "spin_attr/virtual_len",
    "spin_attr/spin_norm",
]

This grouping makes it easier to identify all spin-related attributes at a glance.

deepmd/pt/model/model/spin_model.py (2)

Line range hint 474-497: LGTM! Consider adding documentation for the new parameters.

The addition of comm_dict and extra_nlist_sort parameters enhances the flexibility of the forward_common_lower method. These changes appear to be well-integrated into the existing code.

Consider adding documentation for these new parameters to explain their purpose and usage:

  1. comm_dict: Describe its role in communication and when it should be provided.
  2. extra_nlist_sort: Explain when this boolean flag should be set to True and its impact on the neighbor list sorting.

Line range hint 612-624: LGTM! Consider adding documentation for the new parameter.

The addition of the comm_dict parameter and the dynamic setting of extra_nlist_sort enhance the method's flexibility and maintain consistency with the backbone model's requirements.

Consider adding documentation for the new comm_dict parameter to explain its purpose and usage in the context of the SpinEnergyModel.

source/lmp/pair_deepmd.h (1)

78-78: Consider adding documentation for all_force_mag.

To improve code readability and maintainability, consider adding a brief comment explaining the purpose and usage of the all_force_mag member variable, similar to the existing comments for other member variables.

source/api_cc/include/DeepPotTF.h (1)

378-380: Consider removing commented-out code or adding context

The variables virtual_len and spin_norm are commented out. If they are no longer needed, it would be cleaner to remove them entirely. If they are reserved for future use, consider adding a comment explaining their intended purpose to provide context for other developers.

source/api_cc/include/DeepPotPT.h (1)

Line range hint 356-379: Update documentation for computew overloads combining mixed precision and new parameters.

The overloads of computew methods that handle mixed precision now include force_mag and spin. The documentation does not reflect these changes. To ensure proper usage and understanding, please update the documentation to include descriptions of the new parameters and any implications for mixed precision computations.

source/api_cc/src/DeepPotPT.cc (3)

788-798: Consider handling atom_virial for the spin model

In the compute method starting at line 660, the code related to atom_virial is commented out due to the spin model not being supported yet. If the spin model now supports atom_virial, consider uncommenting and implementing this functionality. If not, provide a clearer comment indicating when this feature will be available.

Clarify the status of atom_virial support in the spin model for better code maintainability.


Line range hint 643-644: Possible code simplification in device checks

In the blocks starting at lines 643-644 and 685-686, there's a check for gpu_enabled to set the device. Consider simplifying the code by initializing device based on the gpu_enabled flag directly during declaration to improve readability.

Example:

torch::Device device = gpu_enabled ? torch::Device(torch::kCUDA, gpu_id) : torch::Device(torch::kCPU);

Also applies to: 685-686


316-331: Consider documenting the new compute method overloads

The newly added compute methods with additional parameters may benefit from inline documentation or comments explaining their purpose, parameters, and usage. This can help future developers understand the differences between overloads and when to use each one.

Add Doxygen-style comments or inline explanations for better clarity.

Also applies to: 660-672

source/lmp/pair_deepmd.cpp (2)

582-586: Consistent use of constant references

In the code:

const vector<double> &dcoord_const = dcoord;
const vector<double> &dspin_const = dspin;
deep_pot.compute(dener, dforce, dforce_mag, dvirial, dcoord_const, dspin_const, dtype, dbox, nghost, lmp_list, ago, fparam, daparam);

While dspin_const and dcoord_const are defined as constant references, consider passing dcoord and dspin directly to deep_pot.compute if they are not modified within the function. This can simplify the code and reduce unnecessary variable declarations.


771-775: Potential misalignment in relative standard deviation computation

In the computation of relative standard deviation:

if (out_rel == 1) {
  deep_pot_model_devi.compute_relative_std_f(std_fm, tmp_avg_fm, eps);
}

Consider whether out_rel should control the relative standard deviation computation for both force and force magnitude (std_f and std_fm). If independent control is desired, introduce a separate flag (e.g., out_rel_fm) for clarity and flexibility.

source/api_c/include/c_api.h (7)

233-247: Add missing documentation for the new function DP_DeepPotComputeNListSP.

The newly added function DP_DeepPotComputeNListSP lacks documentation. Consistent documentation is essential for maintainability and readability. Please add a detailed comment describing the function's purpose, parameters, and expected behavior, similar to the existing function comments.


287-302: Provide documentation for DP_DeepPotComputeNListfSP to maintain consistency.

The function DP_DeepPotComputeNListfSP is missing accompanying documentation. Adding a comprehensive comment will help users understand the function's usage and maintain consistency with the rest of the API.


427-445: Include function comments for DP_DeepPotComputeNList2SP for clarity.

The function DP_DeepPotComputeNList2SP lacks descriptive comments. Please add documentation outlining the function's purpose, parameters, and any special considerations, following the style of existing documented functions.


492-510: Document the new function DP_DeepPotComputeNListf2SP.

To maintain the API's usability, please provide documentation for DP_DeepPotComputeNListf2SP. This should include details about the function's role, its parameters, and any important notes for users.


807-822: Add missing documentation for DP_DeepPotModelDeviComputeNListSP.

The function DP_DeepPotModelDeviComputeNListSP is introduced without accompanying comments. Consistent and thorough documentation aids in code comprehension and maintenance. Please include a comment block describing this function.


860-875: Provide documentation for DP_DeepPotModelDeviComputeNListfSP.

The new function DP_DeepPotModelDeviComputeNListfSP should have a descriptive comment explaining its usage, parameters, and any important details. This ensures consistency and aids other developers.


233-247: Ensure consistent parameter naming for natoms and natom.

There is inconsistency in the naming of the atom count parameter across the new function declarations. Some functions use natoms, while others use natom. For clarity and consistency, it's advisable to standardize on one naming convention.

Apply this diff to rename natom to natoms:

 const int nframes,
-const int natom,
+const int natoms,

Also applies to: 287-302, 427-445, 492-510, 807-822, 860-875, 922-940, 987-1005

source/api_c/src/c_api.cc (2)

1266-1284: Add documentation for the new function DP_DeepPotComputeNListSP

The newly introduced function lacks comments explaining its purpose and usage. Adding documentation will enhance code readability and help other developers understand how to use the spin-supporting API correctly.


Line range hint 1674-1740: Plan for extending multi-frame support with spin in model deviation computations

Similar to earlier functions, DP_DeepPotModelDeviComputeNList2SP currently does not support nframes > 1. If there's a need for processing multiple frames with spin support in model deviation computations, consider implementing this feature.

source/api_c/include/deepmd.hpp (3)

160-179: Add documentation for the _DP_DeepPotComputeNListSP function template

The newly added _DP_DeepPotComputeNListSP function template lacks documentation. Including comments to explain the purpose, parameters, and usage of this function will improve code readability and maintainability.


1141-1194: Include documentation for overloaded compute methods with spin support

The newly added overloaded compute methods that include spin parameters lack explanatory comments. Adding documentation will help other developers understand the purpose and usage of these methods.


1916-2004: Add documentation for spin-aware compute methods in DeepPotModelDevi

The compute methods that handle spin in the DeepPotModelDevi class lack descriptive comments. Providing detailed documentation will aid in understanding the methods' functionalities and parameters.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6fe8dde and 3466e34.

📒 Files selected for processing (13)
  • deepmd/pt/model/model/spin_model.py (4 hunks)
  • deepmd/tf/entrypoints/freeze.py (2 hunks)
  • source/api_c/include/c_api.h (8 hunks)
  • source/api_c/include/deepmd.hpp (6 hunks)
  • source/api_c/src/c_api.cc (10 hunks)
  • source/api_cc/include/DeepPot.h (5 hunks)
  • source/api_cc/include/DeepPotPT.h (4 hunks)
  • source/api_cc/include/DeepPotTF.h (3 hunks)
  • source/api_cc/src/DeepPot.cc (4 hunks)
  • source/api_cc/src/DeepPotPT.cc (4 hunks)
  • source/api_cc/src/DeepPotTF.cc (4 hunks)
  • source/lmp/pair_deepmd.cpp (15 hunks)
  • source/lmp/pair_deepmd.h (1 hunks)
🧰 Additional context used
🔇 Additional comments (27)
deepmd/tf/entrypoints/freeze.py (1)

127-128: LGTM. Can you provide more context on the spin attributes?

The addition of "spin_attr/virtual_len" and "spin_attr/spin_norm" to the list of nodes for the "ener" model type looks good. These changes align with the PR objective of adding support for the spin model.

Could you provide some additional context on what these spin attributes represent and how they are used in the energy calculations?

source/lmp/pair_deepmd.h (1)

78-78: Addition of all_force_mag member variable looks good.

The new member variable std::vector<std::vector<double> > all_force_mag; appropriately extends the PairDeepMD class to store force magnitudes, enhancing its functionality for simulations involving spin handling.

source/api_cc/include/DeepPotPT.h (1)

Line range hint 77-379: Confirm consistency of method signatures across all overloads.

The additions of force_mag and spin parameters across multiple compute and computew method overloads appear consistent. However, please verify that all method signatures are correctly aligned and that the parameter order is maintained uniformly. This helps prevent potential mismatches or confusion during method invocation.

source/api_cc/include/DeepPot.h (5)

162-177: Update method documentation to include force_mag and spin parameters


393-420: Update method documentation to include force_mag and spin parameters


523-554: Update method documentation to include force_mag and spin parameters


827-840: Update documentation for compute methods with added force_mag and spin parameters

The compute methods in the DeepPotModelDevi class have been extended with force_mag and spin parameters. Please update the documentation to reflect these additions for consistency and clarity.


881-897: Update documentation for compute methods with added force_mag and spin parameters

source/api_cc/src/DeepPotPT.cc (3)

341-342: Ensure consistency in TensorOptions dtype settings

In the conditional blocks at lines 341-342 and 683-684, the TensorOptions are set for float32 when VALUETYPE is float. Verify that this pattern is consistently applied throughout the code to prevent any unintended type mismatches.

Also applies to: 683-684


362-365: Validate dimensions of spin_wrapped_Tensor

When creating spin_wrapped_Tensor, ensure that the dimensions match the expected input of the model. Mismatches in tensor dimensions can lead to runtime errors or incorrect computations.

Also applies to: 678-691


315-535: Ensure consistent handling of the spin parameter

The new overloaded compute method includes spin as an input parameter. Please verify that all necessary validations and error handling for spin are implemented. For instance, check if spin has the correct dimensions and whether additional checks are needed for its usage.

Run the following script to search for handling of the spin parameter:

source/lmp/pair_deepmd.cpp (5)

505-505: Initialization of dforce_mag

The vector dforce_mag is declared:

vector<double> dforce_mag(nall * 3);

Ensure that this vector is properly utilized and filled with the correct force magnitude data before being used in subsequent computations to prevent unintended results.


606-608: Ensure correct function overload is called

In the call to deep_pot.compute:

deep_pot.compute(dener, dforce, dforce_mag, dvirial, deatom, dvatom, dcoord, dspin, dtype, dbox, nghost, lmp_list, ago, fparam, daparam);

Verify that the deep_pot.compute function correctly handles the additional dforce_mag and dspin parameters and that the appropriate overload or implementation is being used.


1250-1253: Verify comm_reverse calculation for data communication

The communication reverse size is set as:

if (atom->sp_flag) {
  comm_reverse = numb_models * 3 * 2;
} else {
  comm_reverse = numb_models * 3;
}

Ensure that doubling the size (* 2) when atom->sp_flag is true correctly accounts for the additional spin-related data that needs to be communicated. Validate that this change is consistent throughout the communication routines.


1406-1423: Correct buffer packing in pack_reverse_comm with spin data

In pack_reverse_comm, when atom->sp_flag is true, additional data related to force magnitude is packed:

if (atom->sp_flag) {
  for (i = first; i < last; i++) {
    for (int dd = 0; dd < numb_models; ++dd) {
      buf[m++] = all_force[dd][3 * i + 0];
      buf[m++] = all_force[dd][3 * i + 1];
      buf[m++] = all_force[dd][3 * i + 2];
      buf[m++] = all_force_mag[dd][3 * i + 0];
      buf[m++] = all_force_mag[dd][3 * i + 1];
      buf[m++] = all_force_mag[dd][3 * i + 2];
    }
  }
} else {
  // Existing packing logic
}

Ensure that:

  • The buffer buf is adequately sized to hold the additional data.
  • The order of packing matches the expected order during unpacking.
  • There are no buffer overflows or memory issues.

1435-1454: Consistent buffer unpacking in unpack_reverse_comm

In unpack_reverse_comm, ensure that the unpacking logic accurately mirrors the packing logic:

if (atom->sp_flag) {
  for (i = 0; i < n; i++) {
    j = list[i];
    for (int dd = 0; dd < numb_models; ++dd) {
      all_force[dd][3 * j + 0] += buf[m++];
      all_force[dd][3 * j + 1] += buf[m++];
      all_force[dd][3 * j + 2] += buf[m++];
      all_force_mag[dd][3 * j + 0] += buf[m++];
      all_force_mag[dd][3 * j + 1] += buf[m++];
      all_force_mag[dd][3 * j + 2] += buf[m++];
    }
  }
} else {
  // Existing unpacking logic
}

Verify that:

  • The increments of m are consistent with those in pack_reverse_comm.
  • The data is assigned to the correct indices in all_force and all_force_mag.
  • There are no mismatches that could lead to incorrect force calculations.
source/api_cc/src/DeepPotTF.cc (1)

511-516: Implementation of get_vector method is correct

The get_vector method is correctly implemented and integrates well with the existing code.

source/api_cc/src/DeepPot.cc (5)

221-242: Integration of Spin Support in DeepPot::compute Method

The new overload of the compute method correctly incorporates spin support by introducing the dforce_mag_ and dspin_ parameters. The function calls dp->computew with the appropriate arguments, ensuring that spin effects are accounted for in the computation.


244-262: Addition of Vectorized compute Method with Spin Support

The added vectorized overload of the compute method extends spin support to handle multiple energies and forces. The implementation correctly passes the new dforce_mag_ and dspin_ parameters to dp->computew, enabling spin-aware computations for vector inputs.


264-291: Correct Template Instantiations for New Overloads

The template instantiations for the new compute methods are properly defined for both double and float types. This ensures that the methods supporting spin with different precision levels are available and correctly linked.


954-1012: Extension of DeepPotModelDevi::compute with Spin Parameters

The new compute method overload in DeepPotModelDevi class appropriately adds the dspin_ and all_force_mag parameters to support spin calculations. The loop correctly iterates over all models, invoking the compute method with the new parameters, which ensures consistent spin support across all models.


1073-1140: Addition of Atom-Wise Outputs with Spin Support in DeepPotModelDevi::compute

The extended compute method now includes atom-wise energy and virial outputs alongside spin support. This implementation correctly handles the additional data structures all_atom_energy and all_atom_virial, ensuring that detailed per-atom information is computed and stored for each model.

source/api_c/include/c_api.h (1)

233-247: Verify that memory allocation and deallocation are handled appropriately.

Ensure that any dynamic memory allocations within these functions are properly managed to prevent memory leaks.

To check for dynamic memory allocations in these functions, run:

Also applies to: 287-302, 427-445, 492-510, 807-822, 860-875, 922-940, 987-1005

source/api_c/src/c_api.cc (2)

1304-1323: Ensure consistent naming conventions for spin-related functions

The function DP_DeepPotComputeNListfSP introduces spin support for single precision. Verify that the naming aligns with the project's conventions for indicating single-precision and spin-supporting functions to maintain consistency across the API.

To verify naming consistency, you can search for similar function names:

#!/bin/bash
# Description: Check for naming patterns of spin-supporting functions.

# Test: Search for function names ending with 'SP'. Expect: Consistent naming conventions.
rg --type cpp -o 'void DP_.*SP\('

376-377: Verify the correctness of spin vector initialization

Ensure that the size calculation for the spin_ vector is accurate. The current initialization uses nframes * natoms * 3, which should match the dimensions of the spin input array. Verify that the spin data is provided correctly for all frames and atoms.

To confirm, you can check for inconsistencies in the codebase with:

source/api_c/include/deepmd.hpp (2)

181-227: Ensure consistency in function naming and existence

The specialized functions _DP_DeepPotComputeNListSP<double> and _DP_DeepPotComputeNListSP<float> invoke DP_DeepPotComputeNList2SP and DP_DeepPotComputeNListf2SP respectively. Please verify that these functions are correctly implemented in the C API and follow the established naming conventions.


1045-1049: Verify the size calculation for force_mag

The force_mag vector is resized to nframes * natoms * 3, similar to the force vector. Confirm that this size is appropriate for storing the magnitude of the forces and that it aligns with the output from _DP_DeepPotComputeNListSP.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 21

🧹 Outside diff range and nitpick comments (25)
deepmd/tf/entrypoints/freeze.py (1)

264-265: LGTM. Consider using a constant for spin attribute names.

The addition of "spin_attr/virtual_len" and "spin_attr/spin_norm" to the optional_node list is a good practice. It allows the freezing process to handle graphs that may or may not include these spin-related nodes.

For improved maintainability, consider defining these spin attribute names as constants at the module level. This would ensure consistency and make it easier to update if needed in the future.

Example:

SPIN_ATTR_VIRTUAL_LEN = "spin_attr/virtual_len"
SPIN_ATTR_SPIN_NORM = "spin_attr/spin_norm"

# Then use these constants in both the `_make_node_names` function and the `optional_node` list
deepmd/pt/model/model/spin_model.py (2)

474-475: Consider adding documentation for new parameters.

The new parameters comm_dict and extra_nlist_sort have been added to the forward_common_lower method. To improve code maintainability and usability, consider adding docstring comments explaining the purpose and expected usage of these parameters.

Here's a suggested docstring addition:

def forward_common_lower(
    self,
    extended_coord,
    extended_atype,
    extended_spin,
    nlist,
    mapping: Optional[torch.Tensor] = None,
    fparam: Optional[torch.Tensor] = None,
    aparam: Optional[torch.Tensor] = None,
    do_atomic_virial: bool = False,
    comm_dict: Optional[Dict[str, torch.Tensor]] = None,
    extra_nlist_sort: bool = False,
):
    """
    Forward pass for the lower part of the spin model.

    ...

    Parameters:
    ...
    comm_dict : Optional[Dict[str, torch.Tensor]], optional
        Dictionary for additional communication data, by default None
    extra_nlist_sort : bool, optional
        Whether to perform extra sorting on neighbor lists, by default False
    """
    # ... rest of the method

Line range hint 612-624: LGTM. Consider adding documentation for the new parameter.

The changes look good and are consistent with the modifications in the SpinModel class. The automatic setting of extra_nlist_sort based on the backbone model's requirements is a nice touch for maintaining consistency.

To improve code documentation, consider adding a description for the new comm_dict parameter in the method's docstring.

Here's a suggested docstring addition:

@torch.jit.export
def forward_lower(
    self,
    extended_coord,
    extended_atype,
    extended_spin,
    nlist,
    mapping: Optional[torch.Tensor] = None,
    fparam: Optional[torch.Tensor] = None,
    aparam: Optional[torch.Tensor] = None,
    do_atomic_virial: bool = False,
    comm_dict: Optional[Dict[str, torch.Tensor]] = None,
):
    """
    Lower-level forward pass for the spin energy model.

    ...

    Parameters:
    ...
    comm_dict : Optional[Dict[str, torch.Tensor]], optional
        Dictionary for additional communication data, by default None
    """
    # ... rest of the method
source/api_cc/include/DeepPot.h (5)

146-177: Add missing documentation for new computew methods with force_mag and spin.

The newly added computew methods in the DeepPotBase class lack documentation comments explaining the purpose and usage of the new parameters force_mag and spin. Adding appropriate documentation will improve code readability and maintain consistency with the rest of the codebase.


393-420: Provide documentation for new compute methods with force_mag and spin.

The new template compute methods in the DeepPot class include additional parameters force_mag and spin but lack accompanying documentation. Please add comments to explain the functionality and usage of these methods, maintaining consistency with existing documentation.


523-554: Add documentation for compute methods including force_mag and spin.

The newly introduced compute methods in the DeepPot class that handle atomic energies and virials with additional force_mag and spin parameters lack documentation comments. Providing detailed documentation will enhance clarity and assist other developers in understanding these methods.


827-840: Document new compute methods in DeepPotModelDevi with force_mag and spin.

The DeepPotModelDevi class has new compute methods that include force_mag and spin parameters but lack documentation. Please add comments to explain their purpose and usage, ensuring consistency across the codebase.


881-897: Provide documentation for new compute methods including force_mag and spin.

Please add documentation comments for the newly added methods in the DeepPotModelDevi class to maintain clarity and consistency with the rest of the code.

source/api_cc/src/DeepPotPT.cc (1)

446-446: Fix typographical error in comments

The word "suported" is misspelled. Please correct it to "supported" in the affected comment lines.

Also applies to: 462-462, 477-477, 733-733, 748-748

source/lmp/pair_deepmd.cpp (2)

505-505: Initialization of dforce_mag could be optimized

The vector dforce_mag is initialized with zero values. If the subsequent computation fully populates this vector, the initialization may be unnecessary.

You might consider delaying the initialization until it's necessary or using resize instead of initializing with zeros:

-vector<double> dforce_mag(nall * 3);
+vector<double> dforce_mag;
+dforce_mag.resize(nall * 3);

582-586: Avoid unnecessary copying by passing variables directly

The variables dcoord_const and dspin_const are references to dcoord and dspin, respectively. Since these variables are not modified within the compute call, passing dcoord and dspin directly can simplify the code.

Apply this diff to remove unnecessary variables:

-const vector<double> &dcoord_const = dcoord;
-const vector<double> &dspin_const = dspin;
-deep_pot.compute(dener, dforce, dforce_mag, dvirial, dcoord_const,
-                 dspin_const, dtype, dbox, nghost, lmp_list, ago,
+deep_pot.compute(dener, dforce, dforce_mag, dvirial, dcoord,
+                 dspin, dtype, dbox, nghost, lmp_list, ago,
                  fparam, daparam);
source/api_cc/src/DeepPot.cc (1)

954-1012: Document the usage of dspin_ in DeepPotModelDevi::compute

Consider adding comments or documentation to explain how the dspin_ parameter affects computations within DeepPotModelDevi::compute. This will enhance code readability and assist future contributors in understanding the spin-related computations.

source/api_c/include/c_api.h (9)

233-247: Add missing documentation for DP_DeepPotComputeNListSP function

The function DP_DeepPotComputeNListSP is missing a @brief documentation block. To maintain consistency and help users understand its purpose and usage, please add appropriate documentation similar to other functions in the API.


287-302: Add missing documentation for DP_DeepPotComputeNListfSP function

The function DP_DeepPotComputeNListfSP lacks accompanying documentation. Please include a @brief comment to describe the function's purpose, parameters, and usage.


427-445: Add missing documentation for DP_DeepPotComputeNList2SP function

Please add a @brief documentation block for the DP_DeepPotComputeNList2SP function. This will aid users in understanding its functionality and how it differs from existing functions.


492-510: Add missing documentation for DP_DeepPotComputeNListf2SP function

The function DP_DeepPotComputeNListf2SP is missing documentation. Including a @brief comment will provide clarity on its usage and maintain consistency across the API.


807-822: Add missing documentation for DP_DeepPotModelDeviComputeNListSP function

The DP_DeepPotModelDeviComputeNListSP function lacks a @brief documentation block. Adding documentation will help users understand the function's purpose and parameters.


860-875: Add missing documentation for DP_DeepPotModelDeviComputeNListfSP function

Please include a @brief documentation comment for the DP_DeepPotModelDeviComputeNListfSP function to explain its functionality and usage.


921-940: Add missing documentation for DP_DeepPotModelDeviComputeNList2SP function

The function DP_DeepPotModelDeviComputeNList2SP is missing a documentation block. Providing a @brief comment will enhance understandability and maintain consistency.


987-1005: Add missing documentation for DP_DeepPotModelDeviComputeNListf2SP function

The DP_DeepPotModelDeviComputeNListf2SP function lacks accompanying documentation. Please add a @brief comment to describe its purpose and usage.


Line range hint 233-1005: Ensure consistent use of extern keyword in function declarations

There is inconsistency in the use of the extern keyword across function declarations. Some functions, such as DP_DeepPotModelDeviComputeNList2, are declared without extern, while others include it. To maintain consistency and clarity in the API, please ensure that all public function declarations use the extern keyword appropriately.

source/api_c/src/c_api.cc (4)

354-418: Ensure Consistent Naming Convention for Spin Functions

The newly introduced function DP_DeepPotComputeNList_variant_sp adds spin support. To maintain consistency with existing naming conventions in the codebase, consider renaming the function to use the SP suffix, such as DP_DeepPotComputeNList_variantSP.


758-880: Maintain Consistent Naming for Multi-Model Spin Functions

The function DP_DeepPotModelDeviComputeNList_variant_sp adds spin support for multi-model computations. For consistency, consider renaming it to DP_DeepPotModelDeviComputeNList_variantSP, aligning with the naming convention used elsewhere in the codebase.


778-780: Improve Exception Message for Unsupported Frame Count

The exception message "nframes > 1 not supported yet" is thrown when nframes exceeds 1. Providing additional context or guidance could enhance user understanding. Consider updating the message to indicate whether support for multiple frames is planned or suggest alternative approaches.


1266-1284: Document New Spin Functions for Clarity

The newly added functions (DP_DeepPotComputeNListSP, DP_DeepPotComputeNListfSP, DP_DeepPotComputeNList2SP, DP_DeepPotComputeNListf2SP) introduce spin support. To aid users:

  • Provide detailed documentation for each function.
  • Explain the purpose of the spin parameter.
  • Highlight any differences from their non-spin counterparts.

Also applies to: 1304-1323, 1382-1403, 1426-1447

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6fe8dde and 3466e34.

📒 Files selected for processing (13)
  • deepmd/pt/model/model/spin_model.py (4 hunks)
  • deepmd/tf/entrypoints/freeze.py (2 hunks)
  • source/api_c/include/c_api.h (8 hunks)
  • source/api_c/include/deepmd.hpp (6 hunks)
  • source/api_c/src/c_api.cc (10 hunks)
  • source/api_cc/include/DeepPot.h (5 hunks)
  • source/api_cc/include/DeepPotPT.h (4 hunks)
  • source/api_cc/include/DeepPotTF.h (3 hunks)
  • source/api_cc/src/DeepPot.cc (4 hunks)
  • source/api_cc/src/DeepPotPT.cc (4 hunks)
  • source/api_cc/src/DeepPotTF.cc (4 hunks)
  • source/lmp/pair_deepmd.cpp (15 hunks)
  • source/lmp/pair_deepmd.h (1 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeQL
source/api_cc/include/DeepPotTF.h

[notice] 378-379: Commented-out code
This comment appears to contain commented-out code.


[notice] 385-385: Commented-out code
This comment appears to contain commented-out code.

source/api_cc/src/DeepPotPT.cc

[notice] 356-356: Unused local variable
Variable nloc is not used.


[notice] 462-466: Commented-out code
This comment appears to contain commented-out code.


[notice] 495-495: Commented-out code
This comment appears to contain commented-out code.


[notice] 687-687: Unused local variable
Variable nframes is not used.


[notice] 748-752: Commented-out code
This comment appears to contain commented-out code.


[notice] 754-754: Commented-out code
This comment appears to contain commented-out code.

source/api_cc/src/DeepPotTF.cc

[notice] 893-893: Unused local variable
Variable ret is not used.


[notice] 905-905: Unused local variable
Variable ret is not used.

source/lmp/pair_deepmd.cpp

[notice] 1248-1248: Commented-out code
This comment appears to contain commented-out code.

🔇 Additional comments (25)
deepmd/tf/entrypoints/freeze.py (2)

127-128: LGTM. Can you provide more context on the spin attributes?

The addition of "spin_attr/virtual_len" and "spin_attr/spin_norm" nodes for the "ener" model type is consistent with the PR objectives of adding support for spin models.

Could you provide more information about these spin attributes and how they are used in the energy calculations?


131-131: LGTM. Can you elaborate on the 'aparam_nall' attribute?

The addition of the "fitting_attr/aparam_nall" node for the "ener" model type is in line with the PR objectives.

Could you provide more details about this fitting attribute and its role in the energy calculations or model fitting process?

deepmd/pt/model/model/spin_model.py (1)

Line range hint 1-624: Overall, the changes look good and enhance the model's flexibility.

The modifications to both SpinModel and SpinEnergyModel classes consistently add support for additional communication data (comm_dict) and neighbor list sorting (extra_nlist_sort). These changes likely improve the flexibility and potentially the performance of the spin models.

The implementation appears sound, with good consistency between the two classes. The main suggestion for improvement is to add documentation for the new parameters to enhance code maintainability and usability.

source/lmp/pair_deepmd.h (1)

78-78: Variable all_force_mag Added Correctly

The new member variable all_force_mag is properly declared and follows the existing naming conventions in the class. Its addition aligns with the class structure and should integrate well with the existing code.

source/api_cc/include/DeepPotPT.h (2)

132-148: Duplicate comment: Missing documentation for the new compute method overload

As with the previous compute method overload, this version also lacks documentation. Please include documentation comments for this method to maintain consistency.


315-327: Duplicate comment: Missing documentation for the new computew method overload

This computew method overload also lacks documentation. Please ensure all public methods are properly documented.

source/api_cc/include/DeepPot.h (5)

146-177: Method signatures correctly extend the interface for spin support.

The addition of force_mag and spin parameters to the computew methods appropriately extends the functionality of the DeepPotBase class to support spin models. The parameter types and ordering are consistent with existing methods.


393-420: New methods appropriately extend DeepPot functionality for spin models.

The additions of compute methods with force_mag and spin parameters are consistent with the class design and correctly extend the DeepPot interface to support spin-related computations.


523-554: Method implementations are consistent and correctly extend functionality.

The added methods properly extend the existing functionality to support spin models, maintaining consistency in parameter types and ordering.


827-840: Methods correctly extend functionality for model deviation with spin support.

The added methods in DeepPotModelDevi appropriately extend the class to handle spin models in model deviation calculations.


881-897: Method additions are consistent and extend functionality appropriately.

The new methods correctly extend DeepPotModelDevi to support spin models in computations involving atomic energies and virials.

source/api_cc/src/DeepPotPT.cc (2)

314-536: Implementation of new compute function overload with force_mag and spin

The new overload of the compute function correctly introduces the force_mag and spin parameters. The integration aligns well with the existing code structure and extends the functionality appropriately.

🧰 Tools
🪛 GitHub Check: CodeQL

[notice] 356-356: Unused local variable
Variable nloc is not used.


[notice] 462-466: Commented-out code
This comment appears to contain commented-out code.


[notice] 495-495: Commented-out code
This comment appears to contain commented-out code.


658-798: Implementation of compute function for spin model

The addition of the new compute function overload for the spin model is implemented correctly. The function handles the spin and force_mag parameters appropriately, enhancing the model's capabilities.

🧰 Tools
🪛 GitHub Check: CodeQL

[notice] 687-687: Unused local variable
Variable nframes is not used.


[notice] 748-752: Commented-out code
This comment appears to contain commented-out code.


[notice] 754-754: Commented-out code
This comment appears to contain commented-out code.

source/lmp/pair_deepmd.cpp (2)

1248-1253: Clarify the use of comm_reverse and remove commented-out code

The line // comm_reverse = numb_models * 3; is commented out, and new logic is introduced based on atom->sp_flag. If the old assignment is no longer needed, consider removing it to keep the code clean.

🧰 Tools
🪛 GitHub Check: CodeQL

[notice] 1248-1248: Commented-out code
This comment appears to contain commented-out code.


Line range hint 1406-1454: Possible buffer overflow in communication routines

In both pack_reverse_comm and unpack_reverse_comm, ensure that the buffer buf is sufficiently sized to handle the additional data when atom->sp_flag is true. The added loops increase the amount of data being packed and unpacked.

Run the following script to check buffer sizes in communication routines:

source/api_cc/src/DeepPotTF.cc (2)

511-516: Addition of get_vector Method Correctly Implements Vector Retrieval

The newly added get_vector method extends the DeepPotTF class to retrieve vectors from the session using the provided name. The implementation follows the existing code conventions and templates, ensuring type safety and consistency.


828-1019: Implementation of compute Method with Spin Support

The overloaded compute method effectively adds support for spin calculations. It integrates spin-related parameters and modifies the computational logic to accommodate spin interactions. The method handles the extended data appropriately and maintains compatibility with the existing architecture.

🧰 Tools
🪛 GitHub Check: CodeQL

[notice] 893-893: Unused local variable
Variable ret is not used.


[notice] 905-905: Unused local variable
Variable ret is not used.

source/api_cc/src/DeepPot.cc (5)

221-242: LGTM: Addition of compute functions with spin support

The newly added compute function overloads correctly incorporate the dspin_ parameter to support spin calculations. The implementation follows existing code patterns and maintains consistency.


244-262: LGTM: Overloaded compute function for vector energies with spin

The overloaded compute function handling vectors correctly adds spin support. Parameters are appropriately passed, and the function aligns with the established interface.


488-596: LGTM: Extended compute functions with atomic outputs and spin support

The new compute functions that include datom_energy_, datom_virial_, and spin parameters are implemented consistently with the existing code structure. This extends functionality while maintaining code consistency.


264-319: Ensure template specializations are correctly instantiated

Please verify that the new template specializations for the compute function with spin support are correctly instantiated for both double and float types and that they are properly utilized elsewhere in the codebase.

Run the following script to confirm that instantiations are correctly defined:


1073-1140: Verify correctness of computations involving spin in model deviations

Ensure that the computations in DeepPotModelDevi::compute correctly handle spin when calculating energy, force, and virial deviations across models. It's important that the spin contributions are accurately accounted for in deviation calculations.

Run the following script to check for consistency in deviation computations:

source/api_c/include/c_api.h (1)

921-940: Verify potential impact on backward compatibility due to function updates

The addition of the new function DP_DeepPotModelDeviComputeNList2SP may suggest an update or replacement of the existing DP_DeepPotModelDeviComputeNList2 function. Please verify whether the original function remains available and unmodified. If any existing functions have altered signatures or have been deprecated, consider the impact on users who rely on the previous API and provide guidance or versioning to handle backward compatibility.

source/api_c/src/c_api.cc (2)

1270-1270: Confirm Const Correctness of Spin Parameters

The spin parameter is declared as a const pointer (e.g., const double* spin). Ensure that the data pointed to by spin is not modified within the function. If modifications are necessary, remove the const qualifier.

Review the implementation to ensure spin is treated as read-only.

Also applies to: 1309-1309, 1387-1387, 1430-1430


376-377: Verify the Size of the Spin Vector Initialization

Ensure that the spin vector spin_ is initialized with the correct size of nframes * natoms * 3. A mismatch in size could lead to out-of-bounds access or incorrect computations.

Run the following script to confirm the size of the spin vector:

✅ Verification successful

[/run_scripts]


Verified: Spin Vector Initialization Sizes are Correct

The initialization of spin_ with size nframes * natoms * 3 at lines 376-377 is correct. Additionally, the initialization with natoms * 3 at line 783 is appropriate within its context where nframes is restricted to 1.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the size of the spin vector initialization
# Expected: The size matches nframes * natoms * 3

grep -rn 'std::vector<VALUETYPE> spin_' source/api_c/src/ | grep 'spin'

# Check for correct size calculation in the code

Length of output: 255


Script:

#!/bin/bash
# Description: Extract lines around line 783 in c_api.cc to understand the context of spin_ initialization

# Extract 10 lines before and after line 783
sed -n '773,793p' source/api_c/src/c_api.cc

Length of output: 886

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 26

🧹 Outside diff range and nitpick comments (15)
deepmd/tf/entrypoints/freeze.py (1)

264-265: LGTM. Consider extracting spin attributes to a constant.

The addition of "spin_attr/virtual_len" and "spin_attr/spin_norm" to the optional_node list is consistent with the changes in the _make_node_names function. This improves the robustness of the freezing process for different model configurations.

For better code readability and maintainability, consider extracting the spin attribute names to a constant at the top of the file:

SPIN_ATTR_NODES = [
    "spin_attr/ntypes_spin",
    "spin_attr/virtual_len",
    "spin_attr/spin_norm",
]

Then, you can use this constant in both the _make_node_names function and the optional_node list:

optional_node = [
    "train_attr/min_nbor_dist",
    "fitting_attr/aparam_nall",
    *SPIN_ATTR_NODES,
]

This approach would make it easier to manage these related attributes in the future.

deepmd/pt/model/model/spin_model.py (1)

Line range hint 474-497: LGTM! Consider adding documentation for new parameters.

The changes to forward_common_lower look good. The addition of comm_dict and extra_nlist_sort parameters enhances the method's flexibility.

Consider adding docstring comments to explain the purpose and usage of these new parameters:

  • comm_dict: Explain its role in communication and any expected key-value pairs.
  • extra_nlist_sort: Describe when this should be set to True and its impact on the neighbor list.
source/api_cc/include/DeepPotTF.h (1)

384-384: Consider using smart pointers for extend_firstneigh

The member variable extend_firstneigh is defined as std::vector<int*>. Using raw pointers can lead to memory management issues. Consider using smart pointers or ensuring that the ownership and lifecycle of these pointers are well-managed.

source/api_cc/include/DeepPotPT.h (1)

Line range hint 356-371: Document the new computew method overload with force_mag and spin

The computew method overload at lines 356-371 introduces additional parameters force_mag and spin. Adding comprehensive documentation for this method, including details about all parameters and their purposes, will improve clarity for users and maintain consistency across the API.

source/api_cc/include/DeepPot.h (1)

523-554: Provide default values where appropriate

Consider providing default values for the new parameters force_mag and spin if they are optional. This can help maintain backward compatibility and ease of use for existing code that does not require these parameters.

source/lmp/pair_deepmd.cpp (3)

657-666: Ensure the model deviation functionality is thoroughly tested.

The added code introduces support for model deviation calculations when atom->sp_flag is not set. Ensure that this new functionality is thoroughly tested, covering scenarios with and without eflag_atom or cvflag_atom set.

Consider adding unit tests or integration tests to cover the new model deviation functionality and ensure its correctness.


677-695: Ensure the model deviation functionality is thoroughly tested with spin interactions.

The added code introduces support for model deviation calculations when atom->sp_flag is set, indicating spin interactions. Ensure that this new functionality is thoroughly tested, covering scenarios with and without eflag_atom or cvflag_atom set, and verifying the correctness of the spin-related computations.

Consider adding unit tests or integration tests to cover the new model deviation functionality with spin interactions and ensure its correctness.


848-848: Implement support for spin atomic force output.

The comment indicates that support for spin atomic force output is needed. Implement this functionality to ensure that the atomic forces associated with spin interactions are correctly output when out_each is set to 1.

Do you want me to provide a code snippet that implements the spin atomic force output? I can help generate the necessary code to gather and output the spin atomic forces.

source/api_cc/src/DeepPot.cc (2)

244-263: Add unit tests for the new spin-aware 'compute' methods

The new overloads of the compute method now support spin interactions. To ensure correctness and prevent future regressions, consider adding unit tests that specifically test these new methods with various spin configurations.


1073-1140: Update documentation to reflect new spin capabilities

The addition of spin support in the compute methods is a significant change. Remember to update the documentation and any relevant API references to inform users about the new parameters and functionality.

source/api_c/src/c_api.cc (5)

1266-1284: Suggest adding unit tests for DP_DeepPotComputeNListSP

The new function DP_DeepPotComputeNListSP introduces spin support into the public API. To ensure its correctness and prevent future regressions, consider adding unit tests covering various scenarios, including edge cases.

Would you like assistance in generating unit tests for this function?


1304-1323: Suggest adding unit tests for DP_DeepPotComputeNListfSP

Similarly, the DP_DeepPotComputeNListfSP function extends spin support for single-precision floats. Adding corresponding unit tests would help validate its functionality.

Would you like assistance in creating unit tests for this function?


1425-1448: Suggest adding unit tests for DP_DeepPotComputeNListf2SP

The addition of DP_DeepPotComputeNListf2SP introduces spin support for multi-frame computations with single-precision floats. Adding unit tests will help ensure its reliability.

Would you like assistance in developing unit tests for this function?


1633-1652: Suggest adding unit tests for DP_DeepPotModelDeviComputeNListfSP

To ensure the correctness of the new DP_DeepPotModelDeviComputeNListfSP function, consider adding unit tests that cover various scenarios with single-precision floats.

Would you like help in creating unit tests for this function?


1718-1740: Suggest adding unit tests for DP_DeepPotModelDeviComputeNListf2SP

Adding unit tests for the DP_DeepPotModelDeviComputeNListf2SP function will help verify its functionality with single-precision floats in multi-frame computations.

Do you need assistance in developing unit tests for this function?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6fe8dde and 3466e34.

📒 Files selected for processing (13)
  • deepmd/pt/model/model/spin_model.py (4 hunks)
  • deepmd/tf/entrypoints/freeze.py (2 hunks)
  • source/api_c/include/c_api.h (8 hunks)
  • source/api_c/include/deepmd.hpp (6 hunks)
  • source/api_c/src/c_api.cc (10 hunks)
  • source/api_cc/include/DeepPot.h (5 hunks)
  • source/api_cc/include/DeepPotPT.h (4 hunks)
  • source/api_cc/include/DeepPotTF.h (3 hunks)
  • source/api_cc/src/DeepPot.cc (4 hunks)
  • source/api_cc/src/DeepPotPT.cc (4 hunks)
  • source/api_cc/src/DeepPotTF.cc (4 hunks)
  • source/lmp/pair_deepmd.cpp (15 hunks)
  • source/lmp/pair_deepmd.h (1 hunks)
🧰 Additional context used
🔇 Additional comments (56)
deepmd/tf/entrypoints/freeze.py (3)

127-128: LGTM. Can you provide more context on the new spin attributes?

The addition of "spin_attr/virtual_len" and "spin_attr/spin_norm" to the list of nodes for the "ener" model type looks good. These changes align with the PR objective of adding support for spin models.

Could you please provide some additional context on what these new spin attributes represent and how they are used in the spin model calculations?


Line range hint 1-399: Overall assessment: Changes look good with minor suggestions

The modifications to freeze.py successfully add support for spin attributes in the graph freezing process, aligning well with the PR objectives. The changes are implemented in a backwards-compatible manner and extend the functionality as intended.

Key points:

  1. New spin attributes (virtual_len and spin_norm) are added to both the _make_node_names function and the optional_node list.
  2. The changes improve the robustness of the freezing process for different model configurations.

Suggestions for improvement:

  1. Consider extracting spin attribute names to a constant for better code readability and maintainability.
  2. Verify the consistent usage of these new spin attributes throughout the codebase where spin models are implemented or processed.

Overall, the changes look good and are ready for merging after addressing the minor suggestions and verifying the usage of new spin attributes in the broader codebase.


127-128: Verify usage of new spin attributes in the codebase

The addition of "spin_attr/virtual_len" and "spin_attr/spin_norm" looks good and appears to be backwards compatible. However, it's important to ensure that these new attributes are properly handled in other parts of the codebase where spin models are used.

Let's verify the usage of these new spin attributes:

Please review the output of this script to ensure that the new spin attributes are consistently used throughout the codebase where spin models are implemented or processed.

Also applies to: 264-265

✅ Verification successful

Let's retry searching for the new spin attributes with the correct file type.


Usage of new spin attributes verified successfully

The new spin attributes "spin_attr/virtual_len" and "spin_attr/spin_norm" are consistently used across the codebase and are properly integrated without introducing any issues.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for usage of new spin attributes in the codebase

# Search for "virtual_len" usage
echo "Searching for 'virtual_len' usage:"
rg "virtual_len" --type python

# Search for "spin_norm" usage
echo "Searching for 'spin_norm' usage:"
rg "spin_norm" --type python

# Search for general spin attribute usage
echo "Searching for general spin attribute usage:"
rg "spin_attr" --type python

Length of output: 444


Script:

#!/bin/bash
# Description: Check for usage of new spin attributes in the codebase with corrected file type.

# Search for "virtual_len" usage
echo "Searching for 'virtual_len' usage:"
rg "virtual_len" --type py

# Search for "spin_norm" usage
echo "Searching for 'spin_norm' usage:"
rg "spin_norm" --type py

# Search for general spin attribute usage
echo "Searching for 'spin_attr' usage:"
rg "spin_attr" --type py

Length of output: 3279

deepmd/pt/model/model/spin_model.py (1)

Line range hint 612-624: LGTM! Consistent implementation with parent class.

The addition of the comm_dict parameter to forward_lower in SpinEnergyModel is consistent with the changes in the parent SpinModel class. This maintains a coherent interface across the model hierarchy.

source/lmp/pair_deepmd.h (1)

78-78: Ensure proper initialization and management of all_force_mag

The new member variable all_force_mag has been added. Please verify that it is properly initialized in the constructor and cleared in the destructor if necessary to prevent potential uninitialized access or memory leaks.

source/api_cc/include/DeepPot.h (4)

881-897: Ensure consistency across all compute method overloads

With the addition of new overloads that include force_mag and spin, double-check that all compute methods across the codebase maintain consistent signatures and parameter order where appropriate.

Run the following script to compare all compute method signatures:

#!/bin/bash
# Description: List all compute method signatures for comparison.

# Extract all compute method declarations
rg --type-add 'cpp:h,cpp' --type cpp 'void compute' -A 5

# Review for consistency in parameter lists

393-420: Check for consistency in template specializations

Ensure that all template specializations and usages of the compute function are updated to accommodate the new parameters. Inconsistent templates might lead to compilation errors or unexpected behavior.

Run the following script to identify all usages of compute and verify that they include the new parameters:

#!/bin/bash
# Description: Find all usages of the compute template function and check for new parameters.

# Search for calls to compute functions
rg --type-add 'cpp:h,cpp' --type cpp 'compute<' -A 5

827-840: Verify correct integration of new parameters

Ensure that the implementation of the new compute methods in DeepPotModelDevi correctly processes the force_mag and spin parameters. Incorrect handling could lead to inaccurate calculations or runtime errors.

You can run the following script to check the method implementations:

#!/bin/bash
# Description: Verify implementations of compute methods with force_mag and spin in DeepPotModelDevi.

# Search for compute method definitions in source files
rg --type-add 'cpp:h,cpp' --type cpp 'void DeepPotModelDevi::compute' -A 10

# Look for proper handling of force_mag and spin within these methods

146-161: Ensure implementation in derived classes

Verify that all derived classes of DeepPotBase correctly implement the new computew overloads with force_mag and spin. Missing implementations could lead to runtime errors due to pure virtual method calls.

You can run the following script to check for implementations of the new methods in all derived classes:

source/lmp/pair_deepmd.cpp (16)

606-608: Ensure const-correctness of dcoord and dspin in the compute call.

Passing dcoord and dspin as const references is a good practice to ensure const-correctness and avoid unintended modifications. Verify that the compute method in the DeepPot class is updated to accept these parameters as const references.


1248-1248: Commented-out code

This comment appears to contain commented-out code.

Show more details


1435-1447: Ensure the reverse communication unpacking for spin interactions is correct.

The added code unpacks the force and force magnitude data from the communication buffer when atom->sp_flag is set, indicating spin interactions. Verify that the unpacking order and indexing are correct, and that the received data is correctly accumulated into the all_force and all_force_mag arrays.

To verify, compare the unpacking logic with the corresponding packing logic in pack_reverse_comm:

#!/bin/bash
# Description: Verify reverse communication unpacking for spin interactions is consistent with packing.

# Test: Compare unpacking and packing logic for spin interactions. Expect: Consistent ordering and indexing of force and force magnitude data.
diff -u <(rg --type cpp $'unpack_reverse_comm.*atom->sp_flag' -A 15) <(rg --type cpp $'pack_reverse_comm.*atom->sp_flag' -A 15)

1179-1188: Ensure the output header is correctly formatted.

The added code outputs the header for the model deviation statistics when atom->sp_flag is not set. Verify that the header format is correct, including the column widths and labels, and that it is consistent with the rest of the output.

To verify, search for other occurrences of the header output and compare the format:


830-845: Ensure the spin-related force magnitude statistics are correctly output.

The added code outputs the spin-related force magnitude statistics (all_fm_max, all_fm_min, all_fm_avg) when atom->sp_flag is set. Verify that the output format is correct and consistent with the rest of the output, and that the statistics are converted to the appropriate units using force_unit_cvt_factor.

To verify, search for other occurrences of the spin-related force magnitude statistics and analyze their usage in the output:

✅ Verification successful

Spin-Related Force Magnitude Statistics Output Verified

The spin-related force magnitude statistics (all_fm_max, all_fm_min, all_fm_avg) are correctly output with consistent formatting and appropriate unit conversion using force_unit_cvt_factor.

  • Verified output statements in source/lmp/pair_deepmd.cpp correctly include all_fm_max, all_fm_min, and all_fm_avg.
  • Confirmed that unit conversion is applied before outputting the statistics.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify spin-related force magnitude statistics are correctly output.

# Test: Search for occurrences of spin-related force magnitude statistics in output statements. Expect: Consistent output format and unit conversion.
rg --type cpp $'all_fm_min|all_fm_max|all_fm_avg' -A 5 | rg --type cpp $'fp <<'

Length of output: 280


Script:

#!/bin/bash
# Description: Verify spin-related force magnitude statistics are correctly output.

# Corrected Test: Search for occurrences of spin-related force magnitude statistics in output statements. Expect: Consistent output format and unit conversion.
rg --type cpp 'fp\s*<<[^;]*\ball_fm_min\b|\ball_fm_max\b|\ball_fm_avg\b' -A 5

Length of output: 2358


1406-1417: Ensure the reverse communication packing for spin interactions is correct.

The added code packs the force and force magnitude data into the communication buffer when atom->sp_flag is set, indicating spin interactions. Verify that the packing order and indexing are correct, and that the buffer size is sufficient to accommodate both the force and force magnitude components.

To verify, compare the packing logic with the corresponding unpacking logic in unpack_reverse_comm:


1190-1195: Ensure the output header for spin interactions is correctly formatted.

The added code outputs the header for the model deviation statistics when atom->sp_flag is set, indicating spin interactions. Verify that the header format is correct, including the column widths and labels for the spin-related force magnitudes (max_devi_fm, min_devi_fm, avg_devi_fm), and that it is consistent with the rest of the output.

To verify, search for other occurrences of the header output and compare the format:


1249-1253: Ensure the correct communication size for spin interactions.

The added code sets the comm_reverse size based on whether atom->sp_flag is set, indicating spin interactions. When spin interactions are present, the size is set to numb_models * 3 * 2, accounting for both the force and force magnitude components. Verify that this size is correct and consistent with the data being communicated for spin interactions.

To verify, search for other occurrences of comm_reverse and analyze how it is used in communication:

✅ Verification successful

Communication size for spin interactions is correctly set.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify `comm_reverse` size is consistent with spin interaction data communication.

# Test: Search for occurrences of `comm_reverse` and analyze usage in communication. Expect: Consistent usage with spin interaction data size.
rg --type cpp $'comm_reverse' -A 5

Length of output: 237


Script:

#!/bin/bash
# Description: Search for all occurrences of `comm_reverse` in C++ files and provide context for each match.

rg --type cpp 'comm_reverse' -C 2

Length of output: 893


755-756: Ensure std_fm and tmp_avg_fm are correctly populated and used.

The new variables std_fm and tmp_avg_fm seem to be related to the standard deviation and average of the force magnitudes. Verify that they are correctly populated and used in the appropriate places, such as in the output or analysis of the spin-related forces.

To verify, search for other occurrences of std_fm and tmp_avg_fm and analyze their usage:

✅ Verification successful

[/run_scripts]


std_fm and tmp_avg_fm are correctly populated and used.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify `std_fm` and `tmp_avg_fm` are correctly populated and used.

# Test: Search for occurrences of `std_fm` and `tmp_avg_fm` and analyze usage. Expect: Consistent population and usage in spin-related force output or analysis.
rg --type cpp $'std_fm|tmp_avg_fm' -A 5

Length of output: 280


Script:

#!/bin/bash
# Description: Corrected script to verify `std_fm` and `tmp_avg_fm` are correctly populated and used.

# Test: Search for occurrences of `std_fm` and `tmp_avg_fm` and analyze their usage. Expect: Consistent population and usage in spin-related force output or analysis.
rg --type cpp 'std_fm|tmp_avg_fm' -C 5

Length of output: 2257


770-783: Ensure the spin-related force magnitude statistics are correctly calculated and used.

The added code calculates the minimum, maximum, and average of the force magnitudes when atom->sp_flag is set, indicating spin interactions. Verify that these statistics are correctly calculated using MPI_Reduce and used in the appropriate places, such as in the output or analysis of the spin-related forces.

To verify, search for other occurrences of the spin-related force magnitude statistics and analyze their usage:

✅ Verification successful

Spin-related force magnitude statistics are correctly calculated and used.

The statistics all_fm_min, all_fm_max, and all_fm_avg are consistently calculated using MPI_Reduce and utilized appropriately in the output and analysis of spin-related forces.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify spin-related force magnitude statistics are correctly calculated and used.

# Test: Search for occurrences of spin-related force magnitude statistics and analyze usage. Expect: Consistent calculation using `MPI_Reduce` and usage in output or analysis.
rg --type cpp $'all_fm_min|all_fm_max|all_fm_avg' -A 5

Length of output: 280


Script:

#!/bin/bash
# Description: Verify spin-related force magnitude statistics are correctly calculated and used.

# Corrected Test: Search for occurrences of spin-related force magnitude statistics and analyze usage. Expect: Consistent calculation using `MPI_Reduce` and usage in output or analysis.
rg --type cpp 'all_fm_min|all_fm_max|all_fm_avg' -A 5

Length of output: 2436


765-766: Ensure all_fm_min, all_fm_max, and all_fm_avg are correctly populated and used.

The new variables all_fm_min, all_fm_max, and all_fm_avg seem to be related to the minimum, maximum, and average of the force magnitudes across all processes. Verify that they are correctly populated using MPI_Reduce and used in the appropriate places, such as in the output or analysis of the spin-related forces.

To verify, search for other occurrences of these variables and analyze their usage:

✅ Verification successful

Re-running Verification for Variable Usage


all_fm_min, all_fm_max, and all_fm_avg are correctly populated and used.

The variables all_fm_min, all_fm_max, and all_fm_avg are properly initialized, populated using MPI_Reduce, and utilized in the output for analyzing spin-related forces.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify `all_fm_min`, `all_fm_max`, and `all_fm_avg` are correctly populated and used.

# Test: Search for occurrences of these variables and analyze usage. Expect: Consistent population using `MPI_Reduce` and usage in spin-related force output or analysis.
rg --type cpp $'all_fm_min|all_fm_max|all_fm_avg' -A 5

Length of output: 280


Script:

# 
#!/bin/bash
# Description: Verify `all_fm_min`, `all_fm_max`, and `all_fm_avg` are correctly populated and used.

# Corrected Test: Search for occurrences of these variables and analyze their usage.
rg --type cpp 'all_fm_min|all_fm_max|all_fm_avg' -A 5

Length of output: 2436


703-703: Verify the assignment of dforce_mag from all_force_mag.

Ensure that assigning dforce_mag from all_force_mag[0] is correct and consistent with the expected behavior of the model deviation functionality when spin interactions are involved.

To verify, search for other occurrences of all_force_mag and analyze how it is populated and used:

✅ Verification successful

Verified the assignment of dforce_mag from all_force_mag is correct and consistent with the expected behavior.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify `all_force_mag` population and usage is consistent with `dforce_mag` assignment.

# Test: Search for occurrences of `all_force_mag` and analyze usage. Expect: Consistent population and usage with `dforce_mag` assignment.
rg --type cpp $'all_force_mag' -A 5

Length of output: 280


Script:

#!/bin/bash
# Description: Corrected script to verify `all_force_mag` population and usage consistency.

# Search for exact occurrences of `all_force_mag`
rg --type cpp 'all_force_mag' -A 5

# Additionally, search for possible variants to ensure comprehensive coverage
rg --type cpp 'all_fm_min|all_fm_max|all_fm_avg' -A 5

Length of output: 10874


505-506: Ensure force magnitude vector is correctly populated and used.

The new dforce_mag vector seems to store force magnitudes. Verify that it is correctly populated by the model and used in the appropriate places, such as in the spin force calculations.

To verify, search for other occurrences of dforce_mag and analyze its usage:


493-493: Verify the spin vector calculation.

Ensure that the spin vector calculation dspin[ii * 3 + dd] = sp[ii][dd] * sp[ii][3] is correct and consistent with the expected spin representation in the model.

To verify, search for other occurrences of sp and analyze how the spin data is populated and used:


919-921: Verify the force calculation for spin interactions.

The added code calculates the forces for spin interactions by adding the scaled dforce values to f[ii][dd]. Ensure that this calculation is correct and consistent with the expected force contributions from spin interactions.

To verify, search for other occurrences of f[ii][dd] and analyze how the forces are accumulated:

✅ Verification successful

Force calculation for spin interactions verified successfully in source/lmp/pair_deepmd.cpp lines 919-921. No inconsistencies found with force accumulation for spin interactions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify force calculation for spin interactions is consistent with force accumulation.

# Test: Search for occurrences of `f[ii][dd]` and analyze force accumulation. Expect: Consistent accumulation of spin interaction forces.
rg --type cpp $'f\[ii\]\[dd\]' -A 5

Length of output: 237


Script:

#!/bin/bash
# Description: Search for all occurrences of force accumulation in C++ files to verify consistency in spin interactions.

# Search for any indexed access to 'f' and capture surrounding lines for context.
rg --type cpp 'f\[[0-9]+\]\[[0-9]+\]' -A 5

Length of output: 352


Script:

#!/bin/bash
# Description: Broadly search for any indexed access to 'f' in C++ files to verify force accumulation related to spin interactions.

# Search for any indexed access to 'f' and capture surrounding lines for context.
rg --type cpp 'f\[' -A 5

Length of output: 148492


582-586: Ensure const-correctness of dcoord and dspin in the compute call.

Passing dcoord and dspin as const references is a good practice to ensure const-correctness and avoid unintended modifications. Verify that the compute method in the DeepPot class is updated to accept these parameters as const references.

To verify, check the declaration of the compute method in the DeepPot class:

✅ Verification successful

[/run_scripts]


[/run_scripts]


[/run_scripts]


Const-correctness of dcoord and dspin Verified

All instances of the DeepPot::compute method in the codebase accept dcoord and dspin as const references, ensuring const-correctness.

  • source/api_cc/src/DeepPot.cc lines: 141-148, 227-235, 291-299, 397-405, 497-505, 519-527
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify `compute` method accepts `dcoord` and `dspin` as const references.

# Test: Search for the declaration of the `compute` method. Expect: `dcoord` and `dspin` parameters are const references.
rg --type cpp $'DeepPot::compute\(.*dcoord.*dspin.*\)' -o -r '$1'

Length of output: 280


Script:

#!/bin/bash
# Description: Verify `compute` method accepts `dcoord` and `dspin` as const references.

# Test: Search for the declaration of the `compute` method. Expect: `dcoord` and `dspin` parameters are const references.
rg --type cpp 'DeepPot::compute\((const\s+vector<double>&\s+dcoord, const\s+vector<double>&\s+dspin)' --only-matching

Length of output: 119


Script:

#!/bin/bash
# Description: Locate all declarations of the `DeepPot::compute` method.

# Test: Search for any `DeepPot::compute` method declarations and extract their signatures.
rg --type cpp 'DeepPot::compute\s*\(.*\)' --pretty --context 0 --multiline

Length of output: 76


Script:

#!/bin/bash
# Description: Locate all declarations and definitions of the `DeepPot::compute` method.

# Test: Search for any `DeepPot::compute` method declarations and extract their full signatures.
rg --type cpp 'DeepPot::compute\s*\([^)]*\)' --pretty --multiline

Length of output: 8346

source/api_cc/src/DeepPotTF.cc (1)

511-516: Function get_vector is correctly implemented.

The get_vector method provides a necessary addition to retrieve vectors from the session. The implementation aligns with the existing codebase and follows appropriate template usage.

source/api_cc/src/DeepPot.cc (1)

221-243: ⚠️ Potential issue

Ensure 'dener_' is populated before accessing its first element

In the compute method, you set dener = dener_[0]; without explicitly checking if dener_ has at least one element. While it's likely that dp->computew populates dener_, it's good practice to ensure that dener_ is not empty before accessing dener_[0] to prevent potential out-of-range errors.

Run the following script to verify that dener_ always has at least one element after calling dp->computew:

source/api_c/include/c_api.h (21)

287-302: Add missing documentation for DP_DeepPotComputeNListfSP.

Similar to DP_DeepPotComputeNListSP, this new function lacks a documentation comment block. Please provide detailed documentation to explain the function's purpose, parameters, and any important information.


287-302: Inconsistent parameter naming: natom vs. natoms.

The parameter natoms should be standardized to natom for consistency across the API.


287-302: Ensure consistent parameter order with existing API functions.

The introduction of the spin parameter changes the parameter order. Please ensure consistency or update documentation accordingly.


427-445: Add missing documentation for DP_DeepPotComputeNList2SP.

This function lacks a documentation block. Including detailed documentation will help users understand its usage and parameters.


427-445: Inconsistent parameter naming: natom vs. natoms.

Please standardize the parameter name to natom for consistency.


427-445: Ensure consistent parameter order with existing API functions.

The placement of the spin parameter differs from existing functions. Consider adjusting the parameter order or updating documentation.


492-510: Add missing documentation for DP_DeepPotComputeNListf2SP.

Please add a documentation block for clarity and consistency.


492-510: Inconsistent parameter naming: natom vs. natoms.

Standardize the parameter name to natom.


492-510: Ensure consistent parameter order with existing API functions.

The spin parameter's position should be consistent with other functions.


807-822: Add missing documentation for DP_DeepPotModelDeviComputeNListSP.

Documentation is missing for this new function. Including it will enhance understanding and usability.


807-822: Inconsistent parameter naming: natom vs. natoms.

Please use natom to match existing functions.


807-822: Ensure consistent parameter order with existing API functions.

Review the placement of the spin parameter for consistency.


860-875: Add missing documentation for DP_DeepPotModelDeviComputeNListfSP.

Adding documentation will help users understand this function's usage.


860-875: Inconsistent parameter naming: natom vs. natoms.

Use natom for consistency.


860-875: Ensure consistent parameter order with existing API functions.

Consider adjusting the spin parameter's position.


921-940: Add missing documentation for DP_DeepPotModelDeviComputeNList2SP.

Please include a documentation block for this function.


921-940: Inconsistent parameter naming: natom vs. natoms.

Standardize to natom.


921-940: Ensure consistent parameter order with existing API functions.

Review the parameter order for consistency.


987-1005: Add missing documentation for DP_DeepPotModelDeviComputeNListf2SP.

Documentation is needed for clarity.


987-1005: Inconsistent parameter naming: natom vs. natoms.

Use natom to remain consistent.


987-1005: Ensure consistent parameter order with existing API functions.

Adjust the spin parameter's position for consistency.

source/api_c/src/c_api.cc (6)

354-418: Well-structured implementation of spin support in DP_DeepPotComputeNList_variant_sp

The addition of the DP_DeepPotComputeNList_variant_sp function effectively extends spin support. The implementation follows the existing coding patterns, ensuring consistency and maintainability.


419-454: Template instantiations correctly added for spin variant

The explicit template instantiations for double and float types ensure that the spin variant functions are available for both data types, aligning with the rest of the API.


758-880: Extension of spin support to DP_DeepPotModelDeviComputeNList_variant_sp

The function DP_DeepPotModelDeviComputeNList_variant_sp properly incorporates spin support into the model deviation computations. The handling of inputs and outputs is consistent with the existing codebase.


1382-1404: Spin support extended to multi-frame computations in DP_DeepPotComputeNList2SP

The function DP_DeepPotComputeNList2SP appropriately extends spin support to multi-frame computations. The parameter handling and function structure are consistent with the rest of the API.


1595-1614: Expansion of spin support in DP_DeepPotModelDeviComputeNListSP

The DP_DeepPotModelDeviComputeNListSP function successfully incorporates spin support for model deviation computations. The implementation aligns with the existing code structure.


1674-1696: Spin support in multi-frame model deviation with DP_DeepPotModelDeviComputeNList2SP

The function DP_DeepPotModelDeviComputeNList2SP appropriately extends spin support to multi-frame model deviation computations. The code is well-integrated and maintains consistency.

source/api_c/include/deepmd.hpp (2)

160-180: Addition of spin support in _DP_DeepPotComputeNListSP is correctly implemented

The new template function and its specializations for handling computations with spin are properly defined and aligned with existing code patterns.


391-453: Addition of spin support in _DP_DeepPotModelDeviComputeNListSP is appropriate

The introduction of the template function and its specializations for computations including spin in the DeepPotModelDevi class is correctly structured.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

🧹 Outside diff range and nitpick comments (20)
deepmd/tf/entrypoints/freeze.py (2)

127-128: LGTM. Consider adding documentation for the new spin attributes.

The addition of "spin_attr/virtual_len" and "spin_attr/spin_norm" nodes for the "ener" model type is consistent with the PR objectives of adding LAMMPS support for spin models. This enhancement will allow the frozen graph to include necessary information for spin-related computations.

To improve maintainability, consider adding a brief comment explaining the purpose of these new spin attributes and when they are used.


264-265: LGTM. Consider grouping related optional nodes.

The addition of "spin_attr/virtual_len" and "spin_attr/spin_norm" to the optional_node list is appropriate. This ensures backward compatibility with existing models that may not have these spin attributes.

To improve code readability, consider grouping related optional nodes together. For example:

optional_node = [
    "train_attr/min_nbor_dist",
    "fitting_attr/aparam_nall",
    # Spin-related attributes
    "spin_attr/ntypes_spin",
    "spin_attr/virtual_len",
    "spin_attr/spin_norm",
]

This grouping makes it easier to identify and manage related optional nodes.

deepmd/pt/model/model/spin_model.py (1)

612-613: LGTM! Consider adding a brief comment for comm_dict.

The changes in the SpinEnergyModel class are consistent with those in SpinModel and should improve the model's performance and flexibility for energy calculations in spin systems. The use of self.backbone_model.need_sorted_nlist_for_lower() for extra_nlist_sort is a good practice.

Consider adding a brief comment explaining the purpose of comm_dict for future maintainability. For example:

comm_dict: Optional[Dict[str, torch.Tensor]] = None,  # Dictionary for additional communication data

Also applies to: 623-624

source/api_cc/include/DeepPotTF.h (3)

282-313: Update Documentation for computew Method Overloads

The computew method now includes additional parameters force_mag and spin. To maintain clarity and assist future developers, please update the method's documentation to reflect these new parameters, providing explanations of their purpose and how they influence the computations.


339-358: Add Documentation for New extend Method

The newly introduced extend method lacks documentation. For better maintainability and ease of understanding, please add comprehensive comments explaining the purpose of this method, detailing each parameter, and highlighting any important considerations or usage examples.


368-369: Document the Template Method get_vector

The template method get_vector is added without accompanying documentation. Please include comments that describe the purpose of this method, explain the template and function parameters, and provide any necessary usage details to aid in understanding and future maintenance.

source/api_cc/include/DeepPotPT.h (4)

77-90: Add documentation for the new compute method overload with force_mag and spin parameters

The new overload of the compute method includes additional parameters force_mag and spin. To maintain code readability and help users understand the purpose and usage of these parameters, please add appropriate documentation comments for this method.


132-148: Document the compute method overload with neighbor list parameters and new arguments

This overload of the compute method introduces force_mag, spin, nghost, lmp_list, and ago parameters but lacks accompanying documentation. Please provide detailed documentation comments to explain these parameters and their usage.


304-314: Provide documentation for the new computew method overloads with force_mag and spin

The computew methods added here include force_mag and spin parameters. To ensure consistency and clarity, please document these methods, explaining the purpose of the new parameters.


356-363: Add documentation for the computew method overload with neighbor list parameters and new arguments

This overload of the computew method includes additional parameters force_mag, spin, nghost, inlist, and ago but lacks documentation. Providing detailed comments will aid in understanding and using this method correctly.

source/api_cc/include/DeepPot.h (5)

146-177: Include documentation for new parameters force_mag and spin

The newly added overloads of the computew method in the DeepPotBase class introduce the parameters force_mag and spin. However, the function's documentation does not reflect these additions. Updating the documentation will enhance clarity and maintain consistency.


393-420: Add documentation for new parameters in compute methods

In the DeepPot class, the compute methods now include additional parameters force_mag and spin in their overloads. Please update the function comments to include descriptions of these new parameters to maintain comprehensive documentation.


523-554: Document new parameters force_mag and spin in function comments

The overloads of the compute methods in the DeepPot class have been extended with force_mag and spin. The current documentation does not mention these parameters. Ensuring that all parameters are documented helps users understand the method interfaces fully.


827-840: Update documentation for added parameters in DeepPotModelDevi

The compute method overloads in the DeepPotModelDevi class now accept force_mag and spin as additional parameters. The accompanying documentation should be revised to include these parameters, providing clear guidance on their usage.


881-897: Ensure all new parameters are included in method documentation

The latest overloads of the compute methods in DeepPotModelDevi introduce force_mag and spin but the method comments have not been updated accordingly. For consistency and clarity, please add descriptions of these parameters to the documentation.

source/api_cc/src/DeepPotPT.cc (1)

446-446: Correct the typo 'suported' to 'supported' in comments

There is a typo in the comments at lines 446, 462, 476, 732, and 748: "suported" should be corrected to "supported".

Also applies to: 462-462, 476-476, 732-732, 748-748

source/api_c/src/c_api.cc (2)

1304-1323: Maintain Consistent Naming Conventions

The introduction of DP_DeepPotComputeNListfSP should follow the project's naming conventions. Ensure that the naming is consistent with existing functions to avoid confusion.

Review the function names to confirm they adhere to the established patterns.


1595-1614: Add Documentation for New Functionality

The function DP_DeepPotModelDeviComputeNListSP lacks comments explaining its purpose and usage. Adding documentation will improve code readability and assist future developers.

Include a descriptive comment block above the function declaration.

source/api_c/include/deepmd.hpp (2)

160-203: Add Documentation for Spin Support Functions

The newly added template functions _DP_DeepPotComputeNListSP and their specializations introduce spin support in the computations. To enhance maintainability and readability, please add documentation comments explaining the purpose, parameters, and usage of these functions.


391-452: Add Documentation for DeepPotModelDevi Spin Support Functions

The new template functions _DP_DeepPotModelDeviComputeNListSP and their specializations introduce spin support in the DeepPotModelDevi class. Adding documentation comments will help users understand how to use these functions properly.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6fe8dde and 3466e34.

📒 Files selected for processing (13)
  • deepmd/pt/model/model/spin_model.py (4 hunks)
  • deepmd/tf/entrypoints/freeze.py (2 hunks)
  • source/api_c/include/c_api.h (8 hunks)
  • source/api_c/include/deepmd.hpp (6 hunks)
  • source/api_c/src/c_api.cc (10 hunks)
  • source/api_cc/include/DeepPot.h (5 hunks)
  • source/api_cc/include/DeepPotPT.h (4 hunks)
  • source/api_cc/include/DeepPotTF.h (3 hunks)
  • source/api_cc/src/DeepPot.cc (4 hunks)
  • source/api_cc/src/DeepPotPT.cc (4 hunks)
  • source/api_cc/src/DeepPotTF.cc (4 hunks)
  • source/lmp/pair_deepmd.cpp (15 hunks)
  • source/lmp/pair_deepmd.h (1 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeQL
source/api_cc/include/DeepPotTF.h

[notice] 378-379: Commented-out code
This comment appears to contain commented-out code.


[notice] 385-385: Commented-out code
This comment appears to contain commented-out code.

source/api_cc/src/DeepPotPT.cc

[notice] 356-356: Unused local variable
Variable nloc is not used.


[notice] 462-466: Commented-out code
This comment appears to contain commented-out code.


[notice] 495-495: Commented-out code
This comment appears to contain commented-out code.


[notice] 687-687: Unused local variable
Variable nframes is not used.


[notice] 748-752: Commented-out code
This comment appears to contain commented-out code.


[notice] 754-754: Commented-out code
This comment appears to contain commented-out code.

source/api_cc/src/DeepPotTF.cc

[notice] 893-893: Unused local variable
Variable ret is not used.


[notice] 905-905: Unused local variable
Variable ret is not used.

source/lmp/pair_deepmd.cpp

[notice] 1248-1248: Commented-out code
This comment appears to contain commented-out code.

🔇 Additional comments (29)
deepmd/tf/entrypoints/freeze.py (1)

Line range hint 1-394: Overall, the changes look good and align with the PR objectives.

The modifications to deepmd/tf/entrypoints/freeze.py successfully add support for spin-related attributes in the energy model while maintaining backward compatibility. The code quality is good, and the changes are well-integrated into the existing structure.

Here's a summary of the review:

  1. New spin attributes ("spin_attr/virtual_len" and "spin_attr/spin_norm") have been added to the energy model.
  2. These attributes are properly handled in both the _make_node_names and freeze_graph functions.
  3. Backward compatibility is maintained by adding the new attributes to the optional_node list.

Minor suggestions for improvement include adding brief documentation for the new spin attributes and grouping related optional nodes for better readability.

deepmd/pt/model/model/spin_model.py (2)

Line range hint 1-638: Overall, the changes look good and align with the PR objectives.

The modifications to both SpinModel and SpinEnergyModel classes enhance the flexibility and potentially the performance of the spin models. The implementation is consistent and correct. The addition of comm_dict and extra_nlist_sort parameters should improve LAMMPS support for spin models as intended.

A few minor suggestions:

  1. Verify the consistent usage of new parameters across the codebase.
  2. Consider adding a brief comment explaining the purpose of comm_dict for future maintainability.

Great job on these improvements!


474-476: LGTM! Verify consistent usage of new parameters.

The addition of comm_dict and extra_nlist_sort parameters to the forward_common_lower method enhances the model's flexibility and aligns with the PR objectives. The implementation looks correct.

To ensure consistency, let's verify if these new parameters are used correctly in other parts of the codebase:

Also applies to: 496-497

source/lmp/pair_deepmd.h (1)

78-78: LGTM!

The addition of all_force_mag is appropriate and consistent with the existing member variables.

source/api_cc/include/DeepPotTF.h (1)

118-134: Ensure Consistency with New compute Method Overload

The new compute method overload includes additional parameters force_mag and spin. Please verify that all calls to compute throughout the codebase are updated to match this new signature where appropriate, and ensure that the added parameters are correctly handled in the implementation to prevent any potential runtime errors or mismatches.

To assist in verifying the usage of the compute method, you can run the following script:

✅ Verification successful

All compute method calls are consistent with the new signature.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all usages of the `compute` method to ensure they match the new signature.

rg --type cpp --type c++ -A 2 -B 2 '\.compute\('

Length of output: 78


Script:

#!/bin/bash
# Description: Find all usages of the `compute` method to ensure they match the new signature.

rg --type cpp -A 2 -B 2 '\.compute\('

Length of output: 114850


Script:

#!/bin/bash
# Description: Find all `compute` method calls that do not include `force_mag` and `spin` parameters.

ast-grep --lang cpp --pattern "compute($_, $_, $_, $_, $_, $_, $_, $_, $_, $_, $_, $_, $_, $_)" --match-only

Length of output: 476


Script:

#!/bin/bash
# Description: Find all `compute` method calls that do not include `force_mag` and `spin` parameters.

ast-grep --lang cpp --pattern "compute($_, $_, $_, $_, $_, $_, $_, $_, $_, $_, $_, $_, $_, $_)"

Length of output: 251

source/api_cc/include/DeepPotPT.h (1)

328-341: Ensure consistency in method signatures and parameter ordering in computew overloads

There are multiple overloads of the computew method with varying parameter types and orders. Please verify that the method signatures are consistent and that the parameter ordering is appropriate to prevent confusion and potential misuse.

source/lmp/pair_deepmd.cpp (2)

582-586: Handling spin interactions correctly in force computation.

The function call to deep_pot.compute has been appropriately updated to include dforce_mag and dspin_const, allowing for the computation of spin-related forces. This modification correctly extends the functionality to handle spin interactions.


1406-1423: Ensure correct buffer size and indexing in reverse communication.

In the pack_reverse_comm function (lines 1406-1423), when atom->sp_flag is set, additional spin force data (dforce_mag) is packed into the buffer. Ensure that the buffer size comm_reverse is correctly set to accommodate the extra data and that indexing variable m correctly tracks the buffer positions to prevent buffer overflows or misalignment.

source/api_cc/src/DeepPotTF.cc (2)

511-515: Implementation of get_vector method is correct

The get_vector method correctly retrieves vector data from the session using the provided name.


893-893: Acknowledging past comments on unused variables

The variable ret is assigned but not used beyond an assert statement at lines 893 and 905. Previous review comments have already addressed this issue.

No further action is needed if the previous comments are being addressed.

Also applies to: 905-905

🧰 Tools
🪛 GitHub Check: CodeQL

[notice] 893-893: Unused local variable
Variable ret is not used.

source/api_cc/src/DeepPot.cc (5)

221-243: Correct implementation of new compute method with spin support

The new compute method overloads correctly add parameters for spin (dspin_) and magnetic force (dforce_mag_). The method properly forwards these parameters to dp->computew, enhancing functionality to support spin calculations.


244-263: Consistent addition of vectorized compute method with spin support

The overload of the compute method for vector energies (std::vector<ENERGYTYPE>& dener) is implemented correctly with the new spin parameters. This maintains consistency with the single-energy version and appropriately extends the class's capabilities.


954-1012: Accurate addition of spin support in DeepPotModelDevi::compute

The DeepPotModelDevi class now includes an overloaded compute method that supports spin (dspin_) and magnetic forces (all_force_mag). The implementation correctly loops over numb_models and passes the new parameters to each dps[ii].compute call.


1073-1140: Extension of compute method with atom energies and spin support is sound

The extended compute method in DeepPotModelDevi now supports atom energies, atom virials, and spin parameters. These additions are correctly integrated into the method, enhancing its functionality for spin-related computations.


488-596: Ensure consistency in template instantiations for spin support

The template instantiations for both double and float types for the new compute methods support spin calculations correctly. Verify that these instantiations cover all required use cases and that there are no missing specializations.

To confirm completeness, you might run a check to ensure all necessary template specializations are provided:

✅ Verification successful

Template Instantiations Verified

All necessary template instantiations for double and float types with spin support are present.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all template instantiations for DeepPot::compute with spin support

# Expected: All instantiations for double and float types should be present
rg --type cpp 'template void DeepPot::compute<.*>\(' -A 5 | rg 'dspin_'

Length of output: 479

source/api_c/include/c_api.h (8)

807-821: Verify the usage of the new function in the codebase.

The new function DP_DeepPotModelDeviComputeNListSP looks good. It extends the existing DP_DeepPotModelDeviComputeNList function by adding a spin parameter to support spin computations for the dipole charge modifier.

However, please ensure that all the callers of this function provide the correct arguments, especially the new spin and force_mag parameters.

Run the following script to verify the function usage:

#!/bin/bash
# Description: Verify all function calls to `DP_DeepPotModelDeviComputeNListSP` provide the correct arguments.

# Test: Search for the function usage. Expect: Callers provide all required arguments including `spin` and `force_mag`.
rg --type c -A 5 $'DP_DeepPotModelDeviComputeNListSP'

860-874: Verify the usage of the new function in the codebase.

The new function DP_DeepPotModelDeviComputeNListfSP looks good. It is the float version counterpart of DP_DeepPotModelDeviComputeNListSP and extends the existing DP_DeepPotModelDeviComputeNListf function by adding a spin parameter to support spin computations for the dipole charge modifier.

However, please ensure that all the callers of this function provide the correct arguments, especially the new spin and force_mag parameters.

Run the following script to verify the function usage:

#!/bin/bash
# Description: Verify all function calls to `DP_DeepPotModelDeviComputeNListfSP` provide the correct arguments.

# Test: Search for the function usage. Expect: Callers provide all required arguments including `spin` and `force_mag`.
rg --type c -A 5 $'DP_DeepPotModelDeviComputeNListfSP'

922-939: Verify the usage of the new function in the codebase.

The new function DP_DeepPotModelDeviComputeNList2SP looks good. It extends the existing DP_DeepPotModelDeviComputeNList2 function by adding a spin parameter to support spin computations for the dipole charge modifier with multiple frames.

However, please ensure that all the callers of this function provide the correct arguments, especially the new spin and force_mag parameters.

Run the following script to verify the function usage:

#!/bin/bash
# Description: Verify all function calls to `DP_DeepPotModelDeviComputeNList2SP` provide the correct arguments.

# Test: Search for the function usage. Expect: Callers provide all required arguments including `spin` and `force_mag`.
rg --type c -A 5 $'DP_DeepPotModelDeviComputeNList2SP'

233-247: Verify the usage of the new function in the codebase.

The new function DP_DeepPotComputeNListSP looks good. It extends the existing DP_DeepPotComputeNList function by adding a spin parameter to support spin computations.

However, please ensure that all the callers of this function provide the correct arguments, especially the new spin and force_mag parameters.

Run the following script to verify the function usage:

✅ Verification successful

No usages of DP_DeepPotComputeNListSP found in the codebase.

There are currently no callers of the DP_DeepPotComputeNListSP function to verify argument correctness.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `DP_DeepPotComputeNListSP` provide the correct arguments.

# Test: Search for the function usage. Expect: Callers provide all required arguments including `spin` and `force_mag`.
rg --type c -A 5 $'DP_DeepPotComputeNListSP'

Length of output: 552


492-509: Verify the usage of the new function in the codebase.

The new function DP_DeepPotComputeNListf2SP looks good. It is the float version counterpart of DP_DeepPotComputeNList2SP and extends the existing DP_DeepPotComputeNListf2 function by adding a spin parameter to support spin computations for multiple frames.

However, please ensure that all the callers of this function provide the correct arguments, especially the new spin and force_mag parameters.

Run the following script to verify the function usage:


987-1004: Verify the usage of the new function in the codebase.

The new function DP_DeepPotModelDeviComputeNListf2SP looks good. It is the float version counterpart of DP_DeepPotModelDeviComputeNList2SP and extends the existing DP_DeepPotModelDeviComputeNListf2 function by adding a spin parameter to support spin computations for the dipole charge modifier with multiple frames.

However, please ensure that all the callers of this function provide the correct arguments, especially the new spin and force_mag parameters.

Run the following script to verify the function usage:

✅ Verification successful

No callers of DP_DeepPotModelDeviComputeNListf2SP found.

All usages are correctly implemented or yet to be added.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `DP_DeepPotModelDeviComputeNListf2SP` provide the correct arguments.

# Test: Search for the function usage. Expect: Callers provide all required arguments including `spin` and `force_mag`.
rg --type c -A 5 $'DP_DeepPotModelDeviComputeNListf2SP'

Length of output: 682


Script:

#!/bin/bash
# Description: Verify all function calls to `DP_DeepPotModelDeviComputeNListf2SP` provide the correct arguments.

# Test: Search for the function usage. Expect: Callers provide all required arguments including `spin` and `force_mag`.
rg --type c -A 5 'DP_DeepPotModelDeviComputeNListf2SP'

Length of output: 593


287-301: Verify the usage of the new function in the codebase.

The new function DP_DeepPotComputeNListfSP looks good. It is the float version counterpart of DP_DeepPotComputeNListSP and extends the existing DP_DeepPotComputeNListf function by adding a spin parameter to support spin computations.

However, please ensure that all the callers of this function provide the correct arguments, especially the new spin and force_mag parameters.

Run the following script to verify the function usage:

✅ Verification successful

Function DP_DeepPotComputeNListfSP has no usage in the codebase.
No callers found that need to provide the spin and force_mag arguments.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash 
# Description: Verify all function calls to `DP_DeepPotComputeNListfSP` provide the correct arguments.

# Test: Search for the function usage. Expect: Callers provide all required arguments including `spin` and `force_mag`.
rg --type c -A 5 $'DP_DeepPotComputeNListfSP'

Length of output: 558


Script:

#!/bin/bash
# Description: Correctly verify all function calls to `DP_DeepPotComputeNListfSP` provide the correct arguments.

# Test: Search for the function usage. Expect: Callers provide all required arguments including `spin` and `force_mag`.
rg --type c -A 5 'DP_DeepPotComputeNListfSP'

Length of output: 556


427-444: Verify the usage of the new function in the codebase.

The new function DP_DeepPotComputeNList2SP looks good. It extends the existing DP_DeepPotComputeNList2 function by adding a spin parameter to support spin computations for multiple frames.

However, please ensure that all the callers of this function provide the correct arguments, especially the new spin and force_mag parameters.

Run the following script to verify the function usage:

✅ Verification successful

No usages of DP_DeepPotComputeNList2SP found in the codebase.

Upon verification, there are no existing calls to the new function DP_DeepPotComputeNList2SP. Please ensure that this function is integrated correctly where needed.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `DP_DeepPotComputeNList2SP` provide the correct arguments.

# Test: Search for the function usage. Expect: Callers provide all required arguments including `spin` and `force_mag`.
rg --type c -A 5 $'DP_DeepPotComputeNList2SP'

Length of output: 558

source/api_c/src/c_api.cc (3)

1382-1404: Check Template Instantiations for Completeness

In DP_DeepPotComputeNList2SP, ensure that template instantiations are provided for all required data types (both double and float) to prevent linker errors.


1674-1696: Ensure All Data Types are Supported in New Functions

For DP_DeepPotModelDeviComputeNList2SP, confirm that all necessary data types and template instantiations are correctly implemented.


1266-1284: Verify Integration of New Spin Support Functions

The new function DP_DeepPotComputeNListSP adds spin support. Ensure that all relevant parts of the codebase are updated to utilize this new function where appropriate.

Run the following script to find and review all usages of DP_DeepPotComputeNList:

✅ Verification successful

Memory Management Verified for Large Vectors

The vectors force_mag, atom_energy, and atom_virial are properly managed with the use of the clear() method across relevant source files, ensuring effective memory deallocation and preventing memory leaks.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for proper resizing and clearing of large vectors.

# Search for usage of large vectors without proper memory management.
rg --type cpp --context 5 'std::vector<VALUETYPE>' | grep -E 'force_mag|atom_energy|atom_virial'

Length of output: 290


Script:

#!/bin/bash
# Description: Check for proper memory management of large vectors force_mag, atom_energy, and atom_virial.

# Search for memory management operations on the specified vectors.
rg --type cpp 'force_mag\.(resize|clear|reserve|shrink_to_fit)|atom_energy\.(resize|clear|reserve|shrink_to_fit)|atom_virial\.(resize|clear|reserve|shrink_to_fit)' -C 5

Length of output: 20595

@iProzd iProzd linked an issue Oct 16, 2024 that may be closed by this pull request
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (12)
source/api_cc/include/DeepPot.h (2)

14-14: LGTM: Improved class hierarchy through inheritance

The inheritance structure has been enhanced by deriving from appropriate base classes:

  • DeepPotBase from DeepBaseModelBase
  • DeepPot from DeepBaseModel
  • DeepPotModelDevi from DeepBaseModelDevi

This change promotes better code organization and reuse of common functionality.

Also applies to: 207-207, 529-529


91-91: Minor: Fix documentation formatting

There are instances where spaces are missing after asterisks in documentation comments (e.g., *by should be * by). Consider fixing these for better readability.

Also applies to: 426-426

source/api_cc/include/DeepBaseModel.h (2)

111-143: Add 'override' specifier to overridden methods for clarity and safety

The methods cutoff(), numb_types(), numb_types_spin(), dim_fparam(), dim_aparam(), get_type_map(), and is_aparam_nall() in the DeepBaseModel class override virtual methods from DeepBaseModelBase. Adding the override specifier to these methods enhances code clarity and helps detect potential mismatches in method signatures at compile time.

Apply this diff to add the override specifier:

-  double cutoff() const;
+  double cutoff() const override;

-  int numb_types() const;
+  int numb_types() const override;

-  int numb_types_spin() const;
+  int numb_types_spin() const override;

-  int dim_fparam() const;
+  int dim_fparam() const override;

-  int dim_aparam() const;
+  int dim_aparam() const override;

-  void get_type_map(std::string& type_map);
+  void get_type_map(std::string& type_map) override;

-  bool is_aparam_nall() const;
+  bool is_aparam_nall() const override;

279-280: Clarify the comment for 'dpbases' member variable

The inline comment // change to shared_ptr to make it inheritable associated with dpbases is unclear and could lead to confusion. It's not evident how changing to shared_ptr relates to inheritance. Consider revising the comment to accurately reflect the purpose of using shared_ptr for dpbases.

source/api_cc/include/DeepSpin.h (7)

19-19: Typo in Constructor Definition

In the default constructor for DeepSpinBase, there is an unnecessary semicolon {} at the end. This can be removed for clarity.

Apply this diff to remove the unnecessary semicolon:

- DeepSpinBase() {};
+ DeepSpinBase() {}

448-448: Typo in Documentation Comment

There's a typo in the documentation comment for init. "contrcutor" should be "constructor."

Apply this diff to fix the typo:

- * @brief Initialize the DP model deviation contrcutor.
+ * @brief Initialize the DP model deviation constructor.

62-67: Clarify Documentation for Frame and Atomic Parameters

The comments for fparam and aparam contain duplicated or incomplete sentences, which may cause confusion.

Consider rephrasing the comments for clarity. For example:

- *  nframes x dim_fparam.
- *  dim_fparam. Then all frames are assumed to be provided with the same
- * fparam.
+ * The array can be of size:
+ * - `nframes x dim_fparam` for frame-specific parameters.
+ * - `dim_fparam` if all frames share the same `fparam`.
- *  nframes x natoms x dim_aparam.
- *  natoms x dim_aparam. Then all frames are assumed to be provided with the
- * same aparam.
+ * The array can be of size:
+ * - `nframes x natoms x dim_aparam` for frame-specific atomic parameters.
+ * - `natoms x dim_aparam` if all frames share the same `aparam`.

483-484: Remove Duplicated Sentences in Comment

The comment for aparam in the compute_spin function has duplicated sentences, which might lead to confusion.

Apply this diff to remove the duplication:

- * same aparam. dim_aparam. Then all frames and atoms are provided with the
- * same aparam.
+ * same aparam.

528-529: Remove Duplicated Sentences in Comment

Similar to the previous comment, there's duplicated text in the comment for aparam.

Apply this diff to remove the duplication:

- * same aparam. dim_aparam. Then all frames and atoms are provided with the
- * same aparam.
+ * same aparam.

221-245: Consider Reducing Code Duplication in Template Functions

The compute_spin template functions have multiple overloads with similar signatures and documentation. This duplication can make maintenance harder and increase the potential for inconsistencies.

Consider the following refactoring suggestions:

  • Use Default Arguments or Variadic Templates: If possible, consolidate the overloads by using default arguments or variadic templates to handle optional parameters.
  • Extract Common Functionality: Create a private helper function that contains the shared implementation logic, and have the public functions call this helper with appropriate parameters.

This approach can make the codebase more maintainable and reduce the chance of errors.

Also applies to: 274-303, 332-359, 391-424, 487-501, 532-548


425-426: Review Access Specifier for Member Variable dp

The member variable dp is declared as protected in the DeepSpin class. If there are no derived classes that need direct access to dp, consider changing its access level to private to encapsulate the class's internal implementation details.

Apply this diff if appropriate:

-protected:
+private:
  std::shared_ptr<deepmd::DeepSpinBase> dp;
source/api_cc/include/DeepPotPT.h (1)

Line range hint 166-205: Type inconsistency in computew method parameters

The overloads of the computew method have inconsistent parameter types. The ener parameter is of type std::vector<double>&, while other parameters like force, virial, and atom_energy are std::vector<float>&. Mixing double and float types may lead to precision loss and unexpected behavior due to implicit type conversions.

Consider aligning all parameter types to consistently use either double or float. Here's a suggested change to use double types throughout:

 void computew(std::vector<double>& ener,
-              std::vector<float>& force,
-              std::vector<float>& virial,
-              std::vector<float>& atom_energy,
-              std::vector<float>& atom_virial,
-              const std::vector<float>& coord,
+              std::vector<double>& force,
+              std::vector<double>& virial,
+              std::vector<double>& atom_energy,
+              std::vector<double>& atom_virial,
+              const std::vector<double>& coord,
               const std::vector<int>& atype,
-              const std::vector<float>& box,
-              const std::vector<float>& fparam,
-              const std::vector<float>& aparam,
+              const std::vector<double>& box,
+              const std::vector<double>& fparam,
+              const std::vector<double>& aparam,
               const bool atomic);

If using mixed types is intentional for performance reasons, please document the rationale to clarify this design choice.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 643e202 and d1fd284.

📒 Files selected for processing (6)
  • source/api_c/include/deepmd.hpp (26 hunks)
  • source/api_cc/include/DeepBaseModel.h (1 hunks)
  • source/api_cc/include/DeepPot.h (13 hunks)
  • source/api_cc/include/DeepPotPT.h (3 hunks)
  • source/api_cc/include/DeepSpin.h (1 hunks)
  • source/api_cc/include/DeepSpinPT.h (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • source/api_cc/include/DeepSpinPT.h
🔇 Additional comments (9)
source/api_cc/include/DeepPot.h (2)

581-582: LGTM: Well-structured template parameter additions

The template parameters for the compute methods are well-designed:

  • Type-safe handling of force and virial vectors
  • Consistent parameter ordering across overloads
  • Clear documentation of parameter usage

Also applies to: 614-617, 649-650, 688-691


525-527: LGTM: Proper memory management with smart pointers

The use of std::shared_ptr for managing DeepPot instances is appropriate:

  • Ensures proper memory management
  • Supports polymorphic behavior
  • Thread-safe reference counting

Also applies to: 701-702

source/api_c/include/deepmd.hpp (5)

839-947: LGTM: Well-designed base class implementation

The DeepBaseModel class provides a solid foundation with:

  • Clear separation of concerns
  • Proper memory management
  • Comprehensive error checking
  • Type-safe template implementations

1426-1728: LGTM: Well-implemented DeepSpin class

The DeepSpin class implementation:

  • Follows RAII principles
  • Has comprehensive error handling
  • Provides well-documented compute_spin methods
  • Maintains consistency with the existing codebase

Line range hint 2538-2768: LGTM: Well-implemented DeepSpinModelDevi class

The DeepSpinModelDevi class:

  • Properly extends DeepBaseModelDevi
  • Has robust memory management
  • Implements comprehensive compute_spin methods
  • Maintains consistency with model deviation calculations

Line range hint 98-288: LGTM: Well-implemented template specializations

The template specializations for spin support:

  • Handle both float and double types consistently
  • Maintain proper error checking
  • Follow established patterns for memory management

1506-1545: 🛠️ Refactor suggestion

Add input validation for spin vectors

The compute_spin method should validate that the spin vector has the correct dimensions and values before processing.

Add validation at the start of the method:

  template <typename VALUETYPE, typename ENERGYVTYPE>
  void compute_spin(
      ENERGYVTYPE &ener,
      std::vector<VALUETYPE> &force,
      std::vector<VALUETYPE> &force_mag,
      std::vector<VALUETYPE> &virial,
      const std::vector<VALUETYPE> &coord,
      const std::vector<VALUETYPE> &spin,
      const std::vector<int> &atype,
      const std::vector<VALUETYPE> &box,
      const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
      const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
    unsigned int natoms = atype.size();
    unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
+   // Validate spin vector dimensions
+   if (spin.size() != natoms * 3) {
+     throw deepmd::hpp::deepmd_exception(
+         "Spin vector size must be natoms * 3");
+   }
    assert(nframes * natoms * 3 == coord.size());

Likely invalid or redundant comment.

source/api_cc/include/DeepPotPT.h (2)

19-19: Appropriate addition of virtual destructor

Adding a virtual destructor ensures that derived class destructors are called correctly when deleting objects through base class pointers, preventing potential resource leaks.


Line range hint 77-108: Well-documented addition of compute method overload

The new overload of the compute method incorporates additional parameters (nghost, lmp_list, and ago) with comprehensive documentation for each. This enhances functionality while maintaining clarity.

const std::vector<VALUETYPE> &avg,
const VALUETYPE eps,
const int &stride) {
unsigned ndof = avg.size();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove unused variable ndof

The static analysis tool correctly identifies that the variable 'ndof' is declared but never used.

Remove the unused variable:

-   unsigned ndof = avg.size();
    unsigned nloc = std.size();

Committable suggestion skipped: line range outside the PR's diff.

const std::vector<VALUETYPE>& aparam = std::vector<VALUETYPE>());

protected:
std::vector<std::shared_ptr<deepmd::DeepSpin>> dps;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Typo in Member Variable Declaration

In the DeepSpinModelDevi class, the member variable dps should be initialized properly, especially if it holds important model data.

Ensure that dps is correctly initialized in the constructors to prevent potential null pointer dereferences or undefined behavior.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (4)
source/api_c/include/c_api_internal.h (2)

38-48: Add documentation for the base class and its members.

Please add documentation to explain:

  • The purpose of this base class
  • The meaning and usage of each member variable (dfparam, daparam, aparam_nall)
  • Any invariants or constraints that derived classes must maintain

50-60: Consider extracting common members to a shared base class.

Both DP_DeepBaseModel and DP_DeepBaseModelDevi share identical member variables (dfparam, daparam, aparam_nall). Consider extracting these to a common base class to reduce code duplication.

+struct DP_ModelBase {
+    std::string exception;
+    int dfparam;
+    int daparam;
+    bool aparam_nall;
+};

-struct DP_DeepBaseModel {
+struct DP_DeepBaseModel : DP_ModelBase {
     DP_DeepBaseModel();
     DP_DeepBaseModel(const deepmd::DeepBaseModel& dpbase);
     virtual ~DP_DeepBaseModel() {};
     
     deepmd::DeepBaseModel dpbase;
-    std::string exception;
-    int dfparam;
-    int daparam;
-    bool aparam_nall;
 };

-struct DP_DeepBaseModelDevi {
+struct DP_DeepBaseModelDevi : DP_ModelBase {
     // Similar changes...
source/api_c/include/deepmd.hpp (2)

98-156: LGTM! Consider adding parameter validation for spin vectors.

The template functions for spin computations are well-implemented and follow existing patterns. However, consider adding validation for the spin vector dimensions similar to how coord is validated.

Add dimension checks:

template <typename FPTYPE>
inline void _DP_DeepPotComputeSP(DP_DeepSpin *dp,
                                 const int nframes,
                                 const int natom,
                                 const FPTYPE *coord,
                                 const FPTYPE *spin,
                                 const int *atype,
                                 const FPTYPE *cell,
                                 const FPTYPE *fparam,
                                 const FPTYPE *aparam,
                                 double *energy,
                                 FPTYPE *force,
                                 FPTYPE *force_mag,
                                 FPTYPE *virial,
                                 FPTYPE *atomic_energy,
                                 FPTYPE *atomic_virial) {
+  // Validate spin dimensions
+  assert(nframes * natom * 3 == spin.size());

Line range hint 2529-2756: Consider enhancing documentation for DeepSpinModelDevi class.

The implementation is solid but would benefit from more detailed documentation explaining:

  • The purpose and usage of force_mag in model deviation calculations
  • The relationship between spin and magnetic forces
  • Expected ranges and units for spin vectors

Add detailed documentation:

/**
 * @brief Deep Spin Model Deviation class for calculating uncertainties in spin predictions.
 * 
 * This class extends DeepBaseModelDevi to handle spin-based model deviations including:
 * - Regular forces (force)
 * - Magnetic forces (force_mag) representing spin-spin interactions
 * - Virial calculations
 * 
 * @note Spin vectors should be normalized 3D vectors representing spin directions
 */
class DeepSpinModelDevi : public DeepBaseModelDevi {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d1fd284 and 99e1e05.

📒 Files selected for processing (3)
  • source/api_c/include/c_api_internal.h (2 hunks)
  • source/api_c/include/deepmd.hpp (26 hunks)
  • source/lmp/pair_base.h (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • source/lmp/pair_base.h
🔇 Additional comments (4)
source/api_c/include/c_api_internal.h (3)

5-5: LGTM: Required headers added.

The new includes are necessary for the base model and spin functionality.

Also applies to: 7-7


62-88: LGTM: Well-structured inheritance hierarchy.

The derived classes are correctly implemented with:

  • Proper inheritance from base classes
  • Consistent pattern across all implementations
  • Appropriate member variables for each specific model type

38-88: Verify initialization and usage of new base classes.

Let's verify the implementation consistency across the codebase.

✅ Verification successful

Let me gather more specific information about the initialization and usage patterns.

The previous results show the files are present, but we need to verify the actual implementation patterns to ensure proper initialization and inheritance. This will help us confirm if the base classes are being used correctly and if the member variables are properly initialized.


Based on the results, I can now provide a final response as we have sufficient evidence about the initialization patterns and inheritance implementation.

Base classes are properly implemented and initialized

The verification shows:

  • Base class DP_DeepBaseModel correctly initializes all member variables (dfparam, daparam, aparam_nall) in its constructor using the wrapped deepmd::DeepBaseModel
  • Derived classes like DP_DeepSpin properly inherit and initialize the base class through constructor chaining
  • Member variables are consistently used across both TensorFlow and PyTorch implementations
  • Proper initialization patterns are present in both the C and C++ APIs
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check initialization and usage of new base classes

# Test 1: Check if dfparam, daparam, and aparam_nall are properly initialized
echo "Checking member variable initialization..."
rg -l "dfparam|daparam|aparam_nall" --type cpp

# Test 2: Check for any direct usage of DeepBaseModel
echo "Checking DeepBaseModel usage..."
rg "DeepBaseModel\s*\w+\s*=" --type cpp

# Test 3: Check implementation files for the new classes
echo "Checking implementation files..."
fd -e cpp -e h "Deep(Base|Spin).*\.(cpp|h)$"

Length of output: 1150


Script:

#!/bin/bash
# Check initialization patterns in implementation files
echo "=== Checking DeepBaseModel initialization ==="
rg -A 5 "DP_DeepBaseModel\s*::\s*DP_DeepBaseModel" source/api_c/

echo "=== Checking member initialization patterns ==="
rg "dfparam\s*=|daparam\s*=|aparam_nall\s*=" source/api_c/ source/api_cc/

echo "=== Checking inheritance implementation ==="
ast-grep --pattern 'class $_ : public DP_DeepBaseModel {
  $$$
}'

echo "=== Checking DeepSpin implementation ==="
rg -A 10 "DP_DeepSpin\s*::\s*DP_DeepSpin" source/api_c/

Length of output: 5429

source/api_c/include/deepmd.hpp (1)

839-947: LGTM! Base class implementation is clean and well-structured.

The DeepBaseModel class provides a solid foundation with proper virtual destructor and clear separation of concerns. The spin-related functionality is well-integrated.

Comment on lines 1423 to 1722
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const int nghost,
const InputNlist &lmp_list,
const int &ago,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
assert(nframes * natoms * 3 == coord.size());
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, (aparam_nall ? natoms : (natoms - nghost)),
fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes,
(aparam_nall ? natoms : (natoms - nghost)) * daparam,
aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;
_DP_DeepPotComputeNListSP<VALUETYPE>(dp, nframes, natoms, coord_, spin_,
atype_, box_, nghost, lmp_list.nl, ago,
fparam__, aparam__, ener_, force_,
force_mag_, virial_, nullptr, nullptr);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
};

// support spin
template <typename VALUETYPE, typename ENERGYVTYPE>
void compute_spin(
ENERGYVTYPE &ener,
std::vector<VALUETYPE> &force,
std::vector<VALUETYPE> &force_mag,
std::vector<VALUETYPE> &virial,
std::vector<VALUETYPE> &atom_energy,
std::vector<VALUETYPE> &atom_virial,
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const int nghost,
const InputNlist &lmp_list,
const int &ago,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
assert(nframes * natoms * 3 == coord.size());
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
atom_energy.resize(static_cast<size_t>(nframes) * natoms);
atom_virial.resize(static_cast<size_t>(nframes) * natoms * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
VALUETYPE *atomic_ener_ = &atom_energy[0];
VALUETYPE *atomic_virial_ = &atom_virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, (aparam_nall ? natoms : (natoms - nghost)),
fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes,
(aparam_nall ? natoms : (natoms - nghost)) * daparam,
aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;
_DP_DeepPotComputeNListSP<VALUETYPE>(
dp, nframes, natoms, coord_, spin_, atype_, box_, nghost, lmp_list.nl,
ago, fparam__, aparam__, ener_, force_, force_mag_, virial_,
atomic_ener_, atomic_virial_);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
};

private:
DP_DeepSpin *dp;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation for spin vectors in compute_spin methods.

While the DeepSpin class implementation is solid, it should validate spin vector dimensions and values before computation to prevent potential runtime errors.

Add validation in compute_spin methods:

template <typename VALUETYPE, typename ENERGYVTYPE>
void compute_spin(...) {
    unsigned int natoms = atype.size();
    unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
+   // Validate spin dimensions
+   if (spin.size() != static_cast<size_t>(nframes) * natoms * 3) {
+     throw deepmd::hpp::deepmd_exception(
+         "Spin vector size must be nframes * natoms * 3");
+   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class DeepSpin : public DeepBaseModel {
public:
/**
* @brief Get the number of types.
* @return The number of types.
* @brief DP constructor without initialization.
**/
int numb_types() const {
assert(dp);
return DP_DeepPotGetNumbTypes(dp);
};
DeepSpin() : dp(nullptr) {};
~DeepSpin() {};
/**
* @brief Get the number of types with spin.
* @return The number of types with spin.
* @brief DP constructor with initialization.
* @param[in] model The name of the frozen model file.
* @param[in] gpu_rank The GPU rank.
* @param[in] file_content The content of the frozen model file.
**/
int numb_types_spin() const {
assert(dp);
return DP_DeepPotGetNumbTypesSpin(dp);
DeepSpin(const std::string &model,
const int &gpu_rank = 0,
const std::string &file_content = "")
: dp(nullptr) {
try {
init(model, gpu_rank, file_content);
} catch (...) {
// Clean up and rethrow, as the destructor will not be called
if (dp) {
DP_DeleteDeepSpin(dp);
}
throw;
}
};
/**
* @brief Get the type map (element name of the atom types) of this model.
* @param[out] type_map The type map of this model.
* @brief Initialize the DP.
* @param[in] model The name of the frozen model file.
* @param[in] gpu_rank The GPU rank.
* @param[in] file_content The content of the frozen model file.
**/
void get_type_map(std::string &type_map) {
const char *type_map_c = DP_DeepPotGetTypeMap(dp);
type_map.assign(type_map_c);
DP_DeleteChar(type_map_c);
void init(const std::string &model,
const int &gpu_rank = 0,
const std::string &file_content = "") {
if (dp) {
std::cerr << "WARNING: deepmd-kit should not be initialized twice, do "
"nothing at the second call of initializer"
<< std::endl;
return;
}
dp = DP_NewDeepSpinWithParam2(model.c_str(), gpu_rank, file_content.c_str(),
file_content.size());
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
dfparam = DP_DeepBaseModelGetDimFParam((DP_DeepBaseModel *)dp);
daparam = DP_DeepBaseModelGetDimAParam((DP_DeepBaseModel *)dp);
aparam_nall = DP_DeepBaseModelIsAParamNAll((DP_DeepBaseModel *)dp);
dpbase = (DP_DeepBaseModel *)dp;
};
// support spin
/**
* @brief Print the summary of DeePMD-kit, including the version and the build
* information.
* @param[in] pre The prefix to each line.
*/
void print_summary(const std::string &pre) const {
DP_PrintSummary(pre.c_str());
}
/**
* @brief Get the dimension of the frame parameter.
* @return The dimension of the frame parameter.
**/
int dim_fparam() const {
assert(dp);
return dfparam;
}
/**
* @brief Get the dimension of the atomic parameter.
* @return The dimension of the atomic parameter.
* @brief Evaluate the energy, force, magnetic force and virial by using this
*DP with spin input.
* @param[out] ener The system energy.
* @param[out] force The force on each atom.
* @param[out] force_mag The magnetic force on each atom.
* @param[out] virial The virial.
* @param[in] coord The coordinates of atoms. The array should be of size
*nframes x natoms x 3.
* @param[in] spin The spins of atoms, [0, 0, 0] if no spin. The array should
*be of size nframes x 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 nframes
*x 9 (PBC) or empty (no PBC).
* @param[in] fparam The frame parameter. The array can be of size :
* nframes x dim_fparam.
* dim_fparam. Then all frames are assumed to be provided with the same
*fparam.
* @param[in] aparam The atomic parameter The array can be of size :
* nframes x natoms x dim_aparam.
* natoms x dim_aparam. Then all frames are assumed to be provided with the
*same aparam.
* @warning Natoms should not be zero when computing multiple frames.
**/
int dim_aparam() const {
assert(dp);
return daparam;
}
private:
DP_DeepPot *dp;
int dfparam;
template <typename VALUETYPE, typename ENERGYVTYPE>
void compute_spin(
ENERGYVTYPE &ener,
std::vector<VALUETYPE> &force,
std::vector<VALUETYPE> &force_mag,
std::vector<VALUETYPE> &virial,
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
assert(nframes * natoms * 3 == coord.size());
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, natoms, fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes, natoms * daparam, aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;
_DP_DeepPotComputeSP<VALUETYPE>(dp, nframes, natoms, coord_, spin_, atype_,
box_, fparam__, aparam__, ener_, force_,
force_mag_, virial_, nullptr, nullptr);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
};
/**
* @brief Evaluate the energy, force, magnetic force, virial, atomic energy,
*and atomic virial by using this DP with spin input.
* @param[out] ener The system energy.
* @param[out] force The force on each atom.
* @param[out] force_mag The magnetic force on each atom.
* @param[out] virial The virial.
* @param[out] atom_energy The atomic energy.
* @param[out] atom_virial The atomic virial.
* @param[in] coord The coordinates of atoms. The array should be of size
*nframes x natoms x 3.
* @param[in] spin The spins of atoms, [0, 0, 0] if no spin. The array should
*be of size nframes x 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 nframes
*x 9 (PBC) or empty (no PBC).
* @param[in] fparam The frame parameter. The array can be of size :
* nframes x dim_fparam.
* dim_fparam. Then all frames are assumed to be provided with the same
*fparam.
* @param[in] aparam The atomic parameter The array can be of size :
* nframes x natoms x dim_aparam.
* natoms x dim_aparam. Then all frames are assumed to be provided with the
*same aparam.
* @warning Natoms should not be zero when computing multiple frames.
**/
template <typename VALUETYPE, typename ENERGYVTYPE>
void compute_spin(
ENERGYVTYPE &ener,
std::vector<VALUETYPE> &force,
std::vector<VALUETYPE> &force_mag,
std::vector<VALUETYPE> &virial,
std::vector<VALUETYPE> &atom_energy,
std::vector<VALUETYPE> &atom_virial,
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
assert(nframes * natoms * 3 == coord.size());
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
atom_energy.resize(static_cast<size_t>(nframes) * natoms);
atom_virial.resize(static_cast<size_t>(nframes) * natoms * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
VALUETYPE *atomic_ener_ = &atom_energy[0];
VALUETYPE *atomic_virial_ = &atom_virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, natoms, fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes, natoms * daparam, aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;
_DP_DeepPotComputeSP<VALUETYPE>(
dp, nframes, natoms, coord_, spin_, atype_, box_, fparam__, aparam__,
ener_, force_, force_mag_, virial_, atomic_ener_, atomic_virial_);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
};
// support spin
template <typename VALUETYPE, typename ENERGYVTYPE>
void compute_spin(
ENERGYVTYPE &ener,
std::vector<VALUETYPE> &force,
std::vector<VALUETYPE> &force_mag,
std::vector<VALUETYPE> &virial,
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const int nghost,
const InputNlist &lmp_list,
const int &ago,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
assert(nframes * natoms * 3 == coord.size());
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, (aparam_nall ? natoms : (natoms - nghost)),
fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes,
(aparam_nall ? natoms : (natoms - nghost)) * daparam,
aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;
_DP_DeepPotComputeNListSP<VALUETYPE>(dp, nframes, natoms, coord_, spin_,
atype_, box_, nghost, lmp_list.nl, ago,
fparam__, aparam__, ener_, force_,
force_mag_, virial_, nullptr, nullptr);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
};
// support spin
template <typename VALUETYPE, typename ENERGYVTYPE>
void compute_spin(
ENERGYVTYPE &ener,
std::vector<VALUETYPE> &force,
std::vector<VALUETYPE> &force_mag,
std::vector<VALUETYPE> &virial,
std::vector<VALUETYPE> &atom_energy,
std::vector<VALUETYPE> &atom_virial,
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const int nghost,
const InputNlist &lmp_list,
const int &ago,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
assert(nframes * natoms * 3 == coord.size());
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
atom_energy.resize(static_cast<size_t>(nframes) * natoms);
atom_virial.resize(static_cast<size_t>(nframes) * natoms * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
VALUETYPE *atomic_ener_ = &atom_energy[0];
VALUETYPE *atomic_virial_ = &atom_virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, (aparam_nall ? natoms : (natoms - nghost)),
fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes,
(aparam_nall ? natoms : (natoms - nghost)) * daparam,
aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;
_DP_DeepPotComputeNListSP<VALUETYPE>(
dp, nframes, natoms, coord_, spin_, atype_, box_, nghost, lmp_list.nl,
ago, fparam__, aparam__, ener_, force_, force_mag_, virial_,
atomic_ener_, atomic_virial_);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
};
private:
DP_DeepSpin *dp;
};
template <typename VALUETYPE, typename ENERGYVTYPE>
void compute_spin(
ENERGYVTYPE &ener,
std::vector<VALUETYPE> &force,
std::vector<VALUETYPE> &force_mag,
std::vector<VALUETYPE> &virial,
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
// Validate spin dimensions
if (spin.size() != static_cast<size_t>(nframes) * natoms * 3) {
throw deepmd::hpp::deepmd_exception(
"Spin vector size must be nframes * natoms * 3");
}
assert(nframes * natoms * 3 == coord.size());
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, natoms, fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes, natoms * daparam, aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;
_DP_DeepPotComputeSP<VALUETYPE>(dp, nframes, natoms, coord_, spin_, atype_,
box_, fparam__, aparam__, ener_, force_,
force_mag_, virial_, nullptr, nullptr);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (4)
source/api_c/include/deepmd.hpp (4)

98-156: Add detailed documentation for spin-related template functions.

The new template functions for spin computations lack comprehensive documentation. Consider adding:

  • Description of spin vector format and requirements
  • Units and coordinate system for spin vectors
  • Explanation of force_mag output
 // support spin
+/**
+ * @brief Template function for computing energies and forces with spin support.
+ * @param[in] spin The spin vectors for each atom. Array of size nframes x natoms x 3.
+ *                 Each vector represents the spin direction and magnitude.
+ * @param[out] force_mag The magnetic forces on atoms. Array of size nframes x natoms x 3.
+ */
 template <typename FPTYPE>
 inline void _DP_DeepPotComputeSP(DP_DeepSpin *dp,

220-287: Consider reordering parameters for consistency.

The parameter ordering in _DP_DeepPotComputeNListSP places spin between coord and atype, breaking the established pattern where type-related parameters are grouped together. Consider reordering to maintain consistency with other functions.

 template <typename FPTYPE>
 inline void _DP_DeepPotComputeNListSP(DP_DeepSpin *dp,
                                      const int nframes,
                                      const int natom,
                                      const FPTYPE *coord,
-                                     const FPTYPE *spin,
                                      const int *atype,
+                                     const FPTYPE *spin,
                                      const FPTYPE *cell,

Line range hint 2433-2497: Consider extracting common reshape logic into helper method.

The reshape logic in compute_spin methods is duplicated. Consider extracting it into a helper method to improve maintainability.

+private:
+ template <typename VALUETYPE>
+ void reshape_results(std::vector<double> &ener,
+                     std::vector<std::vector<VALUETYPE>> &force,
+                     std::vector<std::vector<VALUETYPE>> &force_mag,
+                     std::vector<std::vector<VALUETYPE>> &virial,
+                     const std::vector<double> &energy_flat,
+                     const std::vector<VALUETYPE> &force_flat,
+                     const std::vector<VALUETYPE> &force_mag_flat,
+                     const std::vector<VALUETYPE> &virial_flat,
+                     const int natoms) {
+   ener.resize(numb_models);
+   force.resize(numb_models);
+   force_mag.resize(numb_models);
+   virial.resize(numb_models);
+   for (int i = 0; i < numb_models; i++) {
+     ener[i] = energy_flat[i];
+     force[i].resize(static_cast<size_t>(natoms) * 3);
+     force_mag[i].resize(static_cast<size_t>(natoms) * 3);
+     virial[i].resize(9);
+     for (int j = 0; j < natoms * 3; j++) {
+       force[i][j] = force_flat[i * natoms * 3 + j];
+       force_mag[i][j] = force_mag_flat[i * natoms * 3 + j];
+     }
+     for (int j = 0; j < 9; j++) {
+       virial[i][j] = virial_flat[i * 9 + j];
+     }
+   }
+ }

Line range hint 1-97: Add high-level documentation for spin support functionality.

The file would benefit from a comprehensive overview of the spin support functionality at the beginning, including:

  • Purpose and scope of spin support
  • Relationship between spin and non-spin computations
  • Expected data formats and conventions
 /*
 Header-only DeePMD-kit C++ 11 library
 
 This header-only library provides a C++ 11 interface to the DeePMD-kit C API.
+
+Spin Support
+------------
+This library provides comprehensive support for spin-based computations through:
+- Template functions for computing energies and forces with spin
+- DeepSpin class for single model computations
+- DeepSpinModelDevi class for model deviation analysis
+- Spin vectors are expected in format [sx, sy, sz] for each atom
 */
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 99e1e05 and ae98964.

📒 Files selected for processing (1)
  • source/api_c/include/deepmd.hpp (21 hunks)

Comment on lines 1500 to 1539
void compute_spin(
ENERGYVTYPE &ener,
std::vector<VALUETYPE> &force,
std::vector<VALUETYPE> &force_mag,
std::vector<VALUETYPE> &virial,
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
assert(nframes * natoms * 3 == coord.size());
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, natoms, fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes, natoms * daparam, aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;

_DP_DeepPotComputeSP<VALUETYPE>(dp, nframes, natoms, coord_, spin_, atype_,
box_, fparam__, aparam__, ener_, force_,
force_mag_, virial_, nullptr, nullptr);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add validation for spin vector dimensions.

The compute_spin method should validate that the spin vector has the correct dimensions (nframes * natoms * 3) before computation to prevent buffer overflows.

 void compute_spin(...) {
     unsigned int natoms = atype.size();
     unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
     assert(nframes * natoms * 3 == coord.size());
+    assert(nframes * natoms * 3 == spin.size());  // Validate spin dimensions
     if (!box.empty()) {
       assert(box.size() == nframes * 9);
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void compute_spin(
ENERGYVTYPE &ener,
std::vector<VALUETYPE> &force,
std::vector<VALUETYPE> &force_mag,
std::vector<VALUETYPE> &virial,
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
assert(nframes * natoms * 3 == coord.size());
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, natoms, fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes, natoms * daparam, aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;
_DP_DeepPotComputeSP<VALUETYPE>(dp, nframes, natoms, coord_, spin_, atype_,
box_, fparam__, aparam__, ener_, force_,
force_mag_, virial_, nullptr, nullptr);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
};
void compute_spin(
ENERGYVTYPE &ener,
std::vector<VALUETYPE> &force,
std::vector<VALUETYPE> &force_mag,
std::vector<VALUETYPE> &virial,
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
assert(nframes * natoms * 3 == coord.size());
assert(nframes * natoms * 3 == spin.size()); // Validate spin dimensions
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, natoms, fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes, natoms * daparam, aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;
_DP_DeepPotComputeSP<VALUETYPE>(dp, nframes, natoms, coord_, spin_, atype_,
box_, fparam__, aparam__, ener_, force_,
force_mag_, virial_, nullptr, nullptr);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
};

Comment on lines 839 to 947
virtual ~DeepBaseModel() { DP_DeleteDeepBaseModel(dpbase); };

/**
* @brief Get the cutoff radius.
* @return The cutoff radius.
**/
double cutoff() const {
assert(dpbase);
return DP_DeepBaseModelGetCutoff(dpbase);
};
/**
* @brief Get the number of types.
* @return The number of types.
**/
int numb_types() const {
assert(dpbase);
return DP_DeepBaseModelGetNumbTypes(dpbase);
};
/**
* @brief Get the number of types with spin.
* @return The number of types with spin.
**/
int numb_types_spin() const {
assert(dpbase);
return DP_DeepBaseModelGetNumbTypesSpin(dpbase);
};
/**
* @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) {
const char *type_map_c = DP_DeepBaseModelGetTypeMap(dpbase);
type_map.assign(type_map_c);
DP_DeleteChar(type_map_c);
};
/**
* @brief Print the summary of DeePMD-kit, including the version and the build
* information.
* @param[in] pre The prefix to each line.
*/
void print_summary(const std::string &pre) const {
DP_PrintSummary(pre.c_str());
}
/**
* @brief Get the dimension of the frame parameter.
* @return The dimension of the frame parameter.
**/
int dim_fparam() const {
assert(dpbase);
return dfparam;
}
/**
* @brief Get the dimension of the atomic parameter.
* @return The dimension of the atomic parameter.
**/
int dim_aparam() const {
assert(dpbase);
return daparam;
}

protected:
DP_DeepBaseModel *dpbase;
int dfparam;
int daparam;
bool aparam_nall;
template <typename VALUETYPE>
void validate_fparam_aparam(const int &nframes,
const int &nloc,
const std::vector<VALUETYPE> &fparam,
const std::vector<VALUETYPE> &aparam) const {
if (fparam.size() != dfparam &&
fparam.size() != static_cast<size_t>(nframes) * dfparam) {
throw deepmd::hpp::deepmd_exception(
"the dim of frame parameter provided is not consistent with what the "
"model uses");
}

if (aparam.size() != static_cast<size_t>(daparam) * nloc &&
aparam.size() != static_cast<size_t>(nframes) * daparam * nloc) {
throw deepmd::hpp::deepmd_exception(
"the dim of atom parameter provided is not consistent with what the "
"model uses");
}
}
template <typename VALUETYPE>
void tile_fparam_aparam(std::vector<VALUETYPE> &out_param,
const int &nframes,
const int &dparam,
const std::vector<VALUETYPE> &param) const {
if (param.size() == dparam) {
out_param.resize(static_cast<size_t>(nframes) * dparam);
for (int ii = 0; ii < nframes; ++ii) {
std::copy(param.begin(), param.end(),
out_param.begin() + static_cast<std::ptrdiff_t>(ii) * dparam);
}
} else if (param.size() == static_cast<size_t>(nframes) * dparam) {
out_param = param;
}
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for spin-related parameters.

The base model implementation should validate spin-related parameters similar to how it validates fparam and aparam. Consider adding a validation method for spin vectors.

 protected:
  template <typename VALUETYPE>
+ void validate_spin(const int &nframes,
+                    const int &natoms,
+                    const std::vector<VALUETYPE> &spin) const {
+   if (spin.size() != static_cast<size_t>(nframes) * natoms * 3) {
+     throw deepmd::hpp::deepmd_exception(
+         "spin vector size does not match frame and atom count");
+   }
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* @brief Deep Potential Base Model.
**/
class DeepBaseModel {
public:
/**
* @brief DP Base Model constructor without initialization.
**/
DeepBaseModel() : dpbase(nullptr) {};
virtual ~DeepBaseModel() { DP_DeleteDeepBaseModel(dpbase); };
/**
* @brief Get the cutoff radius.
* @return The cutoff radius.
**/
double cutoff() const {
assert(dpbase);
return DP_DeepBaseModelGetCutoff(dpbase);
};
/**
* @brief Get the number of types.
* @return The number of types.
**/
int numb_types() const {
assert(dpbase);
return DP_DeepBaseModelGetNumbTypes(dpbase);
};
/**
* @brief Get the number of types with spin.
* @return The number of types with spin.
**/
int numb_types_spin() const {
assert(dpbase);
return DP_DeepBaseModelGetNumbTypesSpin(dpbase);
};
/**
* @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) {
const char *type_map_c = DP_DeepBaseModelGetTypeMap(dpbase);
type_map.assign(type_map_c);
DP_DeleteChar(type_map_c);
};
/**
* @brief Print the summary of DeePMD-kit, including the version and the build
* information.
* @param[in] pre The prefix to each line.
*/
void print_summary(const std::string &pre) const {
DP_PrintSummary(pre.c_str());
}
/**
* @brief Get the dimension of the frame parameter.
* @return The dimension of the frame parameter.
**/
int dim_fparam() const {
assert(dpbase);
return dfparam;
}
/**
* @brief Get the dimension of the atomic parameter.
* @return The dimension of the atomic parameter.
**/
int dim_aparam() const {
assert(dpbase);
return daparam;
}
protected:
DP_DeepBaseModel *dpbase;
int dfparam;
int daparam;
bool aparam_nall;
template <typename VALUETYPE>
void validate_fparam_aparam(const int &nframes,
const int &nloc,
const std::vector<VALUETYPE> &fparam,
const std::vector<VALUETYPE> &aparam) const {
if (fparam.size() != dfparam &&
fparam.size() != static_cast<size_t>(nframes) * dfparam) {
throw deepmd::hpp::deepmd_exception(
"the dim of frame parameter provided is not consistent with what the "
"model uses");
}
if (aparam.size() != static_cast<size_t>(daparam) * nloc &&
aparam.size() != static_cast<size_t>(nframes) * daparam * nloc) {
throw deepmd::hpp::deepmd_exception(
"the dim of atom parameter provided is not consistent with what the "
"model uses");
}
}
template <typename VALUETYPE>
void tile_fparam_aparam(std::vector<VALUETYPE> &out_param,
const int &nframes,
const int &dparam,
const std::vector<VALUETYPE> &param) const {
if (param.size() == dparam) {
out_param.resize(static_cast<size_t>(nframes) * dparam);
for (int ii = 0; ii < nframes; ++ii) {
std::copy(param.begin(), param.end(),
out_param.begin() + static_cast<std::ptrdiff_t>(ii) * dparam);
}
} else if (param.size() == static_cast<size_t>(nframes) * dparam) {
out_param = param;
}
}
};
/**
* @brief Deep Potential Base Model.
**/
class DeepBaseModel {
public:
/**
* @brief DP Base Model constructor without initialization.
**/
DeepBaseModel() : dpbase(nullptr) {};
virtual ~DeepBaseModel() { DP_DeleteDeepBaseModel(dpbase); };
/**
* @brief Get the cutoff radius.
* @return The cutoff radius.
**/
double cutoff() const {
assert(dpbase);
return DP_DeepBaseModelGetCutoff(dpbase);
};
/**
* @brief Get the number of types.
* @return The number of types.
**/
int numb_types() const {
assert(dpbase);
return DP_DeepBaseModelGetNumbTypes(dpbase);
};
/**
* @brief Get the number of types with spin.
* @return The number of types with spin.
**/
int numb_types_spin() const {
assert(dpbase);
return DP_DeepBaseModelGetNumbTypesSpin(dpbase);
};
/**
* @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) {
const char *type_map_c = DP_DeepBaseModelGetTypeMap(dpbase);
type_map.assign(type_map_c);
DP_DeleteChar(type_map_c);
};
/**
* @brief Print the summary of DeePMD-kit, including the version and the build
* information.
* @param[in] pre The prefix to each line.
*/
void print_summary(const std::string &pre) const {
DP_PrintSummary(pre.c_str());
}
/**
* @brief Get the dimension of the frame parameter.
* @return The dimension of the frame parameter.
**/
int dim_fparam() const {
assert(dpbase);
return dfparam;
}
/**
* @brief Get the dimension of the atomic parameter.
* @return The dimension of the atomic parameter.
**/
int dim_aparam() const {
assert(dpbase);
return daparam;
}
protected:
DP_DeepBaseModel *dpbase;
int dfparam;
int daparam;
bool aparam_nall;
template <typename VALUETYPE>
void validate_fparam_aparam(const int &nframes,
const int &nloc,
const std::vector<VALUETYPE> &fparam,
const std::vector<VALUETYPE> &aparam) const {
if (fparam.size() != dfparam &&
fparam.size() != static_cast<size_t>(nframes) * dfparam) {
throw deepmd::hpp::deepmd_exception(
"the dim of frame parameter provided is not consistent with what the "
"model uses");
}
if (aparam.size() != static_cast<size_t>(daparam) * nloc &&
aparam.size() != static_cast<size_t>(nframes) * daparam * nloc) {
throw deepmd::hpp::deepmd_exception(
"the dim of atom parameter provided is not consistent with what the "
"model uses");
}
}
template <typename VALUETYPE>
void validate_spin(const int &nframes,
const int &natoms,
const std::vector<VALUETYPE> &spin) const {
if (spin.size() != static_cast<size_t>(nframes) * natoms * 3) {
throw deepmd::hpp::deepmd_exception(
"spin vector size does not match frame and atom count");
}
}
template <typename VALUETYPE>
void tile_fparam_aparam(std::vector<VALUETYPE> &out_param,
const int &nframes,
const int &dparam,
const std::vector<VALUETYPE> &param) const {
if (param.size() == dparam) {
out_param.resize(static_cast<size_t>(nframes) * dparam);
for (int ii = 0; ii < nframes; ++ii) {
std::copy(param.begin(), param.end(),
out_param.begin() + static_cast<std::ptrdiff_t>(ii) * dparam);
}
} else if (param.size() == static_cast<size_t>(nframes) * dparam) {
out_param = param;
}
}
};

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (8)
source/api_cc/tests/test_deeppot_tf_spin.cc (1)

42-56: Consider using a configurable test data path.

The hardcoded path "../../tests/infer/deepspin_nlist.pbtxt" makes the test less maintainable and portable. Consider using an environment variable or test configuration file.

Also, remove the extra semicolon after the method definition:

-  };
+  }
source/api_cc/include/DeepSpin.h (2)

43-44: Fix documentation formatting.

There are multiple instances where the documentation has formatting issues with missing spaces after asterisks, causing text to run together. For example:

  • *and should be * and
  • *DP should be * DP

Also applies to: 100-101, 302-303, 356-357, 452-453, 494-495


220-231: Consider adding type constraints to templates.

The template parameter VALUETYPE is used without constraints. Consider adding type traits to ensure only floating-point types are accepted:

-template <typename VALUETYPE>
+template <typename VALUETYPE,
+          typename = std::enable_if_t<std::is_floating_point_v<VALUETYPE>>>

Also applies to: 271-285, 327-340, 384-400, 478-491, 522-537

source/api_cc/src/DeepSpin.cc (2)

30-66: Enhance error handling in initialization

The initialization code should provide more detailed error messages and ensure proper cleanup in case of failures.

Consider these improvements:

 void DeepSpin::init(const std::string& model,
                     const int& gpu_rank,
                     const std::string& file_content) {
   if (inited) {
-    std::cerr << "WARNING: deepmd-kit should not be initialized twice, do "
-                 "nothing at the second call of initializer"
-              << std::endl;
+    std::cerr << "WARNING: DeepSpin instance has already been initialized. "
+                 "Skipping reinitialization attempt for model: " << model
+              << std::endl;
     return;
   }
+  try {
     DPBackend backend;
     if (model.length() >= 4 && model.substr(model.length() - 4) == ".pth") {
       backend = deepmd::DPBackend::PyTorch;
     } else if (model.length() >= 3 && model.substr(model.length() - 3) == ".pb") {
       backend = deepmd::DPBackend::TensorFlow;
     } else {
-      throw deepmd::deepmd_exception("Unsupported model file format");
+      throw deepmd::deepmd_exception("Unsupported model file format: " + model);
     }
     // ... rest of the initialization code ...
     inited = true;
     dpbase = dp;
+  } catch (const std::exception& e) {
+    dp.reset();
+    dpbase.reset();
+    throw;
+  }
 }

70-87: Consider vector pre-allocation for better performance

The compute method creates temporary vectors that could benefit from pre-allocation to reduce memory allocations.

Consider pre-allocating vectors:

 template <typename VALUETYPE>
 void DeepSpin::compute(ENERGYTYPE& dener,
                       std::vector<VALUETYPE>& dforce_,
                       std::vector<VALUETYPE>& dforce_mag_,
                       std::vector<VALUETYPE>& dvirial,
                       const std::vector<VALUETYPE>& dcoord_,
                       const std::vector<VALUETYPE>& dspin_,
                       const std::vector<int>& datype_,
                       const std::vector<VALUETYPE>& dbox,
                       const std::vector<VALUETYPE>& fparam_,
                       const std::vector<VALUETYPE>& aparam_) {
-  std::vector<ENERGYTYPE> dener_;
-  std::vector<VALUETYPE> datom_energy_, datom_virial_;
+  static thread_local std::vector<ENERGYTYPE> dener_(1);
+  static thread_local std::vector<VALUETYPE> datom_energy_, datom_virial_;
   dp->computew(dener_, dforce_, dforce_mag_, dvirial, datom_energy_,
                datom_virial_, dcoord_, dspin_, datype_, dbox, fparam_, aparam_,
                false);
   dener = dener_[0];
 }
source/api_c/include/deepmd.hpp (1)

98-156: Consider reordering parameters for consistency

The spin parameter is placed between coord and atype, breaking the pattern where type-related parameters are grouped together. Consider reordering parameters to maintain consistency with other functions:

-                                 const FPTYPE *coord,
-                                 const FPTYPE *spin,
-                                 const int *atype,
+                                 const FPTYPE *coord, 
+                                 const int *atype,
+                                 const FPTYPE *spin,

Consider adding documentation comments explaining parameters and usage.

source/api_cc/tests/test_deeppot_dpa_pt_spin.cc (2)

93-105: Clean up commented-out code

There are several sections of commented-out code related to expected_v and expected_tot_v. If this code is no longer needed, please remove it to enhance code readability. If it's still relevant, consider uncommenting and updating it accordingly.


113-126: Simplify test methods by accessing class members directly

In the test methods, class data members are assigned to local references (e.g., const std::vector<VALUETYPE>& coord = this->coord;). This introduces repetitive code. Consider accessing class members directly using this->coord to reduce code duplication and improve readability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ae98964 and 2c4ca0d.

📒 Files selected for processing (7)
  • source/api_c/include/deepmd.hpp (21 hunks)
  • source/api_c/src/c_api.cc (15 hunks)
  • source/api_cc/include/DeepSpin.h (1 hunks)
  • source/api_cc/src/DeepSpin.cc (1 hunks)
  • source/api_cc/tests/test_deeppot_dpa_pt_spin.cc (1 hunks)
  • source/api_cc/tests/test_deeppot_tf_spin.cc (1 hunks)
  • source/lmp/pair_deepspin.cpp (1 hunks)
🔇 Additional comments (12)
source/api_cc/tests/test_deeppot_tf_spin.cc (1)

1-15: LGTM! Well-organized includes and proper license header.

The file structure follows best practices with a clear organization of system headers, standard library headers, and project-specific headers.

source/api_cc/include/DeepSpin.h (2)

14-163: LGTM! Well-structured class hierarchy.

The inheritance structure follows the established pattern in the codebase, with clear separation of concerns between base interfaces and implementations.


417-419: Ensure proper initialization of smart pointer members.

Both dp and dps members are using appropriate smart pointers, but their initialization in constructors should be verified to prevent potential null pointer dereferences.

Also applies to: 539-541

source/api_c/include/deepmd.hpp (2)

870-873: LGTM!

The numb_types_spin() method is well-integrated and properly documented.


Line range hint 2368-2595: LGTM!

The DeepSpinModelDevi class implementation is well-structured, properly documented, and correctly handles memory management.

source/api_cc/tests/test_deeppot_dpa_pt_spin.cc (1)

251-268: ⚠️ Potential issue

Update the test model path to ensure portability

The initialization path for the test model file may cause issues in different build environments:

dp.init("../../tests/infer/deeppot_dpa_spin.pth");

Consider updating the path to ensure it correctly references the model file relative to the test file's location. This will enhance portability and prevent file not found errors.

The issue was previously noted but appears to persist.

source/lmp/pair_deepspin.cpp (6)

380-808: Consider refactoring the compute method for better maintainability

The compute method spans over 400 lines, which can make it difficult to read, maintain, and debug. Breaking it down into smaller, well-named helper functions would improve code clarity and maintainability.


419-422: Replace std::cout with LAMMPS error handling

Error messages are printed using std::cout, which is not the recommended practice in LAMMPS. Use error->all(FLERR, "..."); to ensure consistent and proper error reporting.


275-279: Add validation for spin_norm values to prevent division by zero

The spin_norm values should be validated to ensure they are non-zero, preventing potential division by zero errors later in the code.


783-789: Add validation for spin magnitude in force computation

In the force computation, dividing by sp[ii][3] without checking if it's zero could cause runtime errors. Add a check to ensure sp[ii][3] is not zero before performing the division.


817-820: Replace std::cout with LAMMPS error handling

Similar to earlier instances, std::cout is used for error messages. Replace it with error->all(FLERR, "..."); to align with LAMMPS error handling conventions.


782-782: Define physical constants at class level for better reusability

The Planck constant hbar is defined locally within the method. Consider defining it as a class-level constant for better maintainability and reusability across the class.

Comment on lines 16 to 41
template <class VALUETYPE>
class TestInferDeepSpin : public ::testing::Test {
protected:
std::vector<VALUETYPE> coord = {12.83, 2.56, 2.18, 12.09, 2.87, 2.74,
3.51, 2.51, 2.60, 4.27, 3.22, 1.56};
std::vector<VALUETYPE> spin = {0., 0., 1.2737, 0., 0., 1.2737,
0., 0., 0., 0., 0., 0.};
std::vector<int> atype = {0, 0, 1, 1};
std::vector<VALUETYPE> box = {13., 0., 0., 0., 13., 0., 0., 0., 13.};
std::vector<VALUETYPE> expected_e = {-7.314365618560289, -7.313531316181837,
-2.8980532245013997, -2.897373810282277};
std::vector<VALUETYPE> expected_f = {
0.0275132293555514, -0.0112057401883111, -0.0212278132621243,
-0.0229926640905535, 0.0114378553363334, 0.019670014885563,
0.0086502856137601, 0.0088926283192558, -0.0127014507822769,
-0.013170850878758, -0.009124743467278, 0.0142592491588383};
std::vector<VALUETYPE> expected_fm = {
0.0066245455049449, -0.0023055088004378, 0.0294608578045521,
-0.0041979452385972, 0.0025775020220167, 0.0316295420619988,
0.0000000000000000, 0.00000000000000000, 0.00000000000000000,
0.0000000000000000, 0.00000000000000000, 0.00000000000000000};
int natoms;
double expected_tot_e;

deepmd::DeepSpin dp;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation for test data consistency.

The test data should be validated to ensure consistent dimensions:

  • coord.size() should be natoms * 3
  • spin.size() should be natoms * 3
  • box.size() should be 9

Add these validations in the SetUp method:

  natoms = expected_e.size();
+ ASSERT_EQ(coord.size(), natoms * 3) << "Coordinates size mismatch";
+ ASSERT_EQ(spin.size(), natoms * 3) << "Spin size mismatch";
+ ASSERT_EQ(atype.size(), natoms) << "Atom types size mismatch";
+ ASSERT_EQ(box.size(), 9) << "Box size should be 9";

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 87 to 114
TYPED_TEST(TestInferDeepSpin, cpu_build_nlist_atomic) {
using VALUETYPE = TypeParam;
const std::vector<VALUETYPE>& coord = this->coord;
const std::vector<VALUETYPE>& spin = this->spin;
std::vector<int>& atype = this->atype;
std::vector<VALUETYPE>& box = this->box;
std::vector<VALUETYPE>& expected_e = this->expected_e;
std::vector<VALUETYPE>& expected_f = this->expected_f;
std::vector<VALUETYPE>& expected_fm = this->expected_fm;
int& natoms = this->natoms;
double& expected_tot_e = this->expected_tot_e;
deepmd::DeepSpin& dp = this->dp;
double ener;
std::vector<VALUETYPE> force, force_mag, virial, atom_ener, atom_vir;
dp.compute(ener, force, force_mag, virial, atom_ener, atom_vir, coord, spin,
atype, box);
EXPECT_EQ(force.size(), natoms * 3);
EXPECT_EQ(force_mag.size(), natoms * 3);
// EXPECT_EQ(atom_ener.size(), natoms);
EXPECT_LT(fabs(ener - expected_tot_e), EPSILON);
for (int ii = 0; ii < natoms * 3; ++ii) {
EXPECT_LT(fabs(force[ii] - expected_f[ii]), EPSILON);
EXPECT_LT(fabs(force_mag[ii] - expected_fm[ii]), EPSILON);
}
for (int ii = 0; ii < natoms; ++ii) {
EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), EPSILON);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance test coverage and structure.

The test case needs the following improvements:

  1. Uncomment the atom_ener size check (as noted in previous reviews)
  2. Add validation for atom_vir dimensions and values
  3. Structure the test into logical sections

Apply this diff to improve the test:

   dp.compute(ener, force, force_mag, virial, atom_ener, atom_vir, coord, spin,
              atype, box);
+  // Size validations
   EXPECT_EQ(force.size(), natoms * 3);
   EXPECT_EQ(force_mag.size(), natoms * 3);
-  // EXPECT_EQ(atom_ener.size(), natoms);
+  EXPECT_EQ(atom_ener.size(), natoms);
+  EXPECT_EQ(atom_vir.size(), natoms * 9) << "Atomic virial tensor size mismatch";

+  // Energy validation
   EXPECT_LT(fabs(ener - expected_tot_e), EPSILON);
+  for (int ii = 0; ii < natoms; ++ii) {
+    EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), EPSILON);
+  }

+  // Force validation
   for (int ii = 0; ii < natoms * 3; ++ii) {
     EXPECT_LT(fabs(force[ii] - expected_f[ii]), EPSILON);
     EXPECT_LT(fabs(force_mag[ii] - expected_fm[ii]), EPSILON);
   }

-  for (int ii = 0; ii < natoms; ++ii) {
-    EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), EPSILON);
+  // Virial validation
+  for (int ii = 0; ii < natoms * 9; ++ii) {
+    EXPECT_LT(fabs(atom_vir[ii]), EPSILON) << "Atomic virial component mismatch";
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
TYPED_TEST(TestInferDeepSpin, cpu_build_nlist_atomic) {
using VALUETYPE = TypeParam;
const std::vector<VALUETYPE>& coord = this->coord;
const std::vector<VALUETYPE>& spin = this->spin;
std::vector<int>& atype = this->atype;
std::vector<VALUETYPE>& box = this->box;
std::vector<VALUETYPE>& expected_e = this->expected_e;
std::vector<VALUETYPE>& expected_f = this->expected_f;
std::vector<VALUETYPE>& expected_fm = this->expected_fm;
int& natoms = this->natoms;
double& expected_tot_e = this->expected_tot_e;
deepmd::DeepSpin& dp = this->dp;
double ener;
std::vector<VALUETYPE> force, force_mag, virial, atom_ener, atom_vir;
dp.compute(ener, force, force_mag, virial, atom_ener, atom_vir, coord, spin,
atype, box);
EXPECT_EQ(force.size(), natoms * 3);
EXPECT_EQ(force_mag.size(), natoms * 3);
// EXPECT_EQ(atom_ener.size(), natoms);
EXPECT_LT(fabs(ener - expected_tot_e), EPSILON);
for (int ii = 0; ii < natoms * 3; ++ii) {
EXPECT_LT(fabs(force[ii] - expected_f[ii]), EPSILON);
EXPECT_LT(fabs(force_mag[ii] - expected_fm[ii]), EPSILON);
}
for (int ii = 0; ii < natoms; ++ii) {
EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), EPSILON);
}
}
TYPED_TEST(TestInferDeepSpin, cpu_build_nlist_atomic) {
using VALUETYPE = TypeParam;
const std::vector<VALUETYPE>& coord = this->coord;
const std::vector<VALUETYPE>& spin = this->spin;
std::vector<int>& atype = this->atype;
std::vector<VALUETYPE>& box = this->box;
std::vector<VALUETYPE>& expected_e = this->expected_e;
std::vector<VALUETYPE>& expected_f = this->expected_f;
std::vector<VALUETYPE>& expected_fm = this->expected_fm;
int& natoms = this->natoms;
double& expected_tot_e = this->expected_tot_e;
deepmd::DeepSpin& dp = this->dp;
double ener;
std::vector<VALUETYPE> force, force_mag, virial, atom_ener, atom_vir;
dp.compute(ener, force, force_mag, virial, atom_ener, atom_vir, coord, spin,
atype, box);
// Size validations
EXPECT_EQ(force.size(), natoms * 3);
EXPECT_EQ(force_mag.size(), natoms * 3);
EXPECT_EQ(atom_ener.size(), natoms);
EXPECT_EQ(atom_vir.size(), natoms * 9) << "Atomic virial tensor size mismatch";
// Energy validation
EXPECT_LT(fabs(ener - expected_tot_e), EPSILON);
for (int ii = 0; ii < natoms; ++ii) {
EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), EPSILON);
}
// Force validation
for (int ii = 0; ii < natoms * 3; ++ii) {
EXPECT_LT(fabs(force[ii] - expected_f[ii]), EPSILON);
EXPECT_LT(fabs(force_mag[ii] - expected_fm[ii]), EPSILON);
}
// Virial validation
for (int ii = 0; ii < natoms * 9; ++ii) {
EXPECT_LT(fabs(atom_vir[ii]), EPSILON) << "Atomic virial component mismatch";
}
}

Comment on lines +220 to +231
template <typename VALUETYPE>
void compute(ENERGYTYPE& ener,
std::vector<VALUETYPE>& force,
std::vector<VALUETYPE>& force_mag,
std::vector<VALUETYPE>& virial,
const std::vector<VALUETYPE>& coord,
const std::vector<VALUETYPE>& spin,
const std::vector<int>& atype,
const std::vector<VALUETYPE>& box,
const std::vector<VALUETYPE>& fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE>& aparam = std::vector<VALUETYPE>());
template <typename VALUETYPE>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation for array dimensions.

The compute methods accept various input arrays but lack validation of their dimensions. Consider adding checks to ensure:

  • coord array size matches natoms * 3
  • spin array size matches natoms * 3
  • box array size matches 9
  • fparam and aparam dimensions match their expected sizes

Example validation for one of the compute methods:

template <typename VALUETYPE>
void compute(...) {
  const size_t natoms = atype.size();
  if (coord.size() != natoms * 3) {
    throw std::invalid_argument("coord size does not match 3 * natoms");
  }
  if (spin.size() != natoms * 3) {
    throw std::invalid_argument("spin size does not match 3 * natoms");
  }
  if (box.size() != 9) {
    throw std::invalid_argument("box size does not match 9");
  }
  // ... rest of the implementation
}

Also applies to: 271-285, 327-340, 384-400, 478-491, 522-537

Comment on lines +345 to +366
template <typename VALUETYPE>
void DeepSpin::compute(ENERGYTYPE& dener,
std::vector<VALUETYPE>& dforce_,
std::vector<VALUETYPE>& dforce_mag_,
std::vector<VALUETYPE>& dvirial,
std::vector<VALUETYPE>& datom_energy_,
std::vector<VALUETYPE>& datom_virial_,
const std::vector<VALUETYPE>& dcoord_,
const std::vector<VALUETYPE>& dspin_,
const std::vector<int>& datype_,
const std::vector<VALUETYPE>& dbox,
const int nghost,
const InputNlist& lmp_list,
const int& ago,
const std::vector<VALUETYPE>& fparam_,
const std::vector<VALUETYPE>& aparam__) {
std::vector<ENERGYTYPE> dener_;
dp->computew(dener_, dforce_, dforce_mag_, dvirial, datom_energy_,
datom_virial_, dcoord_, dspin_, datype_, dbox, nghost, lmp_list,
ago, fparam_, aparam__, true);
dener = dener_[0];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation for neighbor list parameters

The compute method with neighbor lists should validate its input parameters before processing.

Add validation checks:

 template <typename VALUETYPE>
 void DeepSpin::compute(ENERGYTYPE& dener,
                       std::vector<VALUETYPE>& dforce_,
                       std::vector<VALUETYPE>& dforce_mag_,
                       std::vector<VALUETYPE>& dvirial,
                       std::vector<VALUETYPE>& datom_energy_,
                       std::vector<VALUETYPE>& datom_virial_,
                       const std::vector<VALUETYPE>& dcoord_,
                       const std::vector<VALUETYPE>& dspin_,
                       const std::vector<int>& datype_,
                       const std::vector<VALUETYPE>& dbox,
                       const int nghost,
                       const InputNlist& lmp_list,
                       const int& ago,
                       const std::vector<VALUETYPE>& fparam_,
                       const std::vector<VALUETYPE>& aparam__) {
+  if (nghost < 0) {
+    throw deepmd::deepmd_exception("Invalid nghost value: " + std::to_string(nghost));
+  }
+  if (ago < 0) {
+    throw deepmd::deepmd_exception("Invalid ago value: " + std::to_string(ago));
+  }
   std::vector<ENERGYTYPE> dener_;
   dp->computew(dener_, dforce_, dforce_mag_, dvirial, datom_energy_,
                datom_virial_, dcoord_, dspin_, datype_, dbox, nghost, lmp_list,
                ago, fparam_, aparam__, true);
   dener = dener_[0];
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
template <typename VALUETYPE>
void DeepSpin::compute(ENERGYTYPE& dener,
std::vector<VALUETYPE>& dforce_,
std::vector<VALUETYPE>& dforce_mag_,
std::vector<VALUETYPE>& dvirial,
std::vector<VALUETYPE>& datom_energy_,
std::vector<VALUETYPE>& datom_virial_,
const std::vector<VALUETYPE>& dcoord_,
const std::vector<VALUETYPE>& dspin_,
const std::vector<int>& datype_,
const std::vector<VALUETYPE>& dbox,
const int nghost,
const InputNlist& lmp_list,
const int& ago,
const std::vector<VALUETYPE>& fparam_,
const std::vector<VALUETYPE>& aparam__) {
std::vector<ENERGYTYPE> dener_;
dp->computew(dener_, dforce_, dforce_mag_, dvirial, datom_energy_,
datom_virial_, dcoord_, dspin_, datype_, dbox, nghost, lmp_list,
ago, fparam_, aparam__, true);
dener = dener_[0];
}
template <typename VALUETYPE>
void DeepSpin::compute(ENERGYTYPE& dener,
std::vector<VALUETYPE>& dforce_,
std::vector<VALUETYPE>& dforce_mag_,
std::vector<VALUETYPE>& dvirial,
std::vector<VALUETYPE>& datom_energy_,
std::vector<VALUETYPE>& datom_virial_,
const std::vector<VALUETYPE>& dcoord_,
const std::vector<VALUETYPE>& dspin_,
const std::vector<int>& datype_,
const std::vector<VALUETYPE>& dbox,
const int nghost,
const InputNlist& lmp_list,
const int& ago,
const std::vector<VALUETYPE>& fparam_,
const std::vector<VALUETYPE>& aparam__) {
if (nghost < 0) {
throw deepmd::deepmd_exception("Invalid nghost value: " + std::to_string(nghost));
}
if (ago < 0) {
throw deepmd::deepmd_exception("Invalid ago value: " + std::to_string(ago));
}
std::vector<ENERGYTYPE> dener_;
dp->computew(dener_, dforce_, dforce_mag_, dvirial, datom_energy_,
datom_virial_, dcoord_, dspin_, datype_, dbox, nghost, lmp_list,
ago, fparam_, aparam__, true);
dener = dener_[0];
}

Comment on lines +492 to +521
// support spin
// nlist, no atomic
template <typename VALUETYPE>
void DeepSpinModelDevi::compute(
std::vector<ENERGYTYPE>& all_energy,
std::vector<std::vector<VALUETYPE>>& all_force,
std::vector<std::vector<VALUETYPE>>& all_force_mag,
std::vector<std::vector<VALUETYPE>>& all_virial,
const std::vector<VALUETYPE>& dcoord_,
const std::vector<VALUETYPE>& dspin_,
const std::vector<int>& datype_,
const std::vector<VALUETYPE>& dbox,
const int nghost,
const InputNlist& lmp_list,
const int& ago,
const std::vector<VALUETYPE>& fparam,
const std::vector<VALUETYPE>& aparam_) {
if (numb_models == 0) {
return;
}
all_energy.resize(numb_models);
all_force.resize(numb_models);
all_force_mag.resize(numb_models);
all_virial.resize(numb_models);
for (unsigned ii = 0; ii < numb_models; ++ii) {
dps[ii]->compute(all_energy[ii], all_force[ii], all_force_mag[ii],
all_virial[ii], dcoord_, dspin_, datype_, dbox, nghost,
lmp_list, ago, fparam, aparam_);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize model computation using parallel processing

The compute method sequentially processes multiple models, which could be parallelized for better performance.

Consider using parallel execution:

+#include <execution>
+#include <algorithm>

 template <typename VALUETYPE>
 void DeepSpinModelDevi::compute(
     std::vector<ENERGYTYPE>& all_energy,
     std::vector<std::vector<VALUETYPE>>& all_force,
     std::vector<std::vector<VALUETYPE>>& all_force_mag,
     std::vector<std::vector<VALUETYPE>>& all_virial,
     const std::vector<VALUETYPE>& dcoord_,
     const std::vector<VALUETYPE>& dspin_,
     const std::vector<int>& datype_,
     const std::vector<VALUETYPE>& dbox,
     const int nghost,
     const InputNlist& lmp_list,
     const int& ago,
     const std::vector<VALUETYPE>& fparam,
     const std::vector<VALUETYPE>& aparam_) {
   if (numb_models == 0) {
     return;
   }
   all_energy.resize(numb_models);
   all_force.resize(numb_models);
   all_force_mag.resize(numb_models);
   all_virial.resize(numb_models);
-  for (unsigned ii = 0; ii < numb_models; ++ii) {
-    dps[ii]->compute(all_energy[ii], all_force[ii], all_force_mag[ii],
-                     all_virial[ii], dcoord_, dspin_, datype_, dbox, nghost,
-                     lmp_list, ago, fparam, aparam_);
-  }
+  std::vector<unsigned> indices(numb_models);
+  std::iota(indices.begin(), indices.end(), 0);
+  std::for_each(std::execution::par_unseq, indices.begin(), indices.end(),
+    [&](unsigned ii) {
+      dps[ii]->compute(all_energy[ii], all_force[ii], all_force_mag[ii],
+                       all_virial[ii], dcoord_, dspin_, datype_, dbox, nghost,
+                       lmp_list, ago, fparam, aparam_);
+    });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// support spin
// nlist, no atomic
template <typename VALUETYPE>
void DeepSpinModelDevi::compute(
std::vector<ENERGYTYPE>& all_energy,
std::vector<std::vector<VALUETYPE>>& all_force,
std::vector<std::vector<VALUETYPE>>& all_force_mag,
std::vector<std::vector<VALUETYPE>>& all_virial,
const std::vector<VALUETYPE>& dcoord_,
const std::vector<VALUETYPE>& dspin_,
const std::vector<int>& datype_,
const std::vector<VALUETYPE>& dbox,
const int nghost,
const InputNlist& lmp_list,
const int& ago,
const std::vector<VALUETYPE>& fparam,
const std::vector<VALUETYPE>& aparam_) {
if (numb_models == 0) {
return;
}
all_energy.resize(numb_models);
all_force.resize(numb_models);
all_force_mag.resize(numb_models);
all_virial.resize(numb_models);
for (unsigned ii = 0; ii < numb_models; ++ii) {
dps[ii]->compute(all_energy[ii], all_force[ii], all_force_mag[ii],
all_virial[ii], dcoord_, dspin_, datype_, dbox, nghost,
lmp_list, ago, fparam, aparam_);
}
}
// support spin
// nlist, no atomic
#include <execution>
#include <algorithm>
template <typename VALUETYPE>
void DeepSpinModelDevi::compute(
std::vector<ENERGYTYPE>& all_energy,
std::vector<std::vector<VALUETYPE>>& all_force,
std::vector<std::vector<VALUETYPE>>& all_force_mag,
std::vector<std::vector<VALUETYPE>>& all_virial,
const std::vector<VALUETYPE>& dcoord_,
const std::vector<VALUETYPE>& dspin_,
const std::vector<int>& datype_,
const std::vector<VALUETYPE>& dbox,
const int nghost,
const InputNlist& lmp_list,
const int& ago,
const std::vector<VALUETYPE>& fparam,
const std::vector<VALUETYPE>& aparam_) {
if (numb_models == 0) {
return;
}
all_energy.resize(numb_models);
all_force.resize(numb_models);
all_force_mag.resize(numb_models);
all_virial.resize(numb_models);
std::vector<unsigned> indices(numb_models);
std::iota(indices.begin(), indices.end(), 0);
std::for_each(std::execution::par_unseq, indices.begin(), indices.end(),
[&](unsigned ii) {
dps[ii]->compute(all_energy[ii], all_force[ii], all_force_mag[ii],
all_virial[ii], dcoord_, dspin_, datype_, dbox, nghost,
lmp_list, ago, fparam, aparam_);
});
}

Comment on lines +220 to +287
// support spin
template <typename FPTYPE>
inline void _DP_DeepPotComputeNListSP(DP_DeepSpin *dp,
const int nframes,
const int natom,
const FPTYPE *coord,
const FPTYPE *spin,
const int *atype,
const FPTYPE *cell,
const int nghost,
const DP_Nlist *nlist,
const int ago,
const FPTYPE *fparam,
const FPTYPE *aparam,
double *energy,
FPTYPE *force,
FPTYPE *force_mag,
FPTYPE *virial,
FPTYPE *atomic_energy,
FPTYPE *atomic_virial);

template <>
inline void _DP_DeepPotComputeNListSP<double>(DP_DeepSpin *dp,
const int nframes,
const int natom,
const double *coord,
const double *spin,
const int *atype,
const double *cell,
const int nghost,
const DP_Nlist *nlist,
const int ago,
const double *fparam,
const double *aparam,
double *energy,
double *force,
double *force_mag,
double *virial,
double *atomic_energy,
double *atomic_virial) {
DP_DeepSpinComputeNList2(dp, nframes, natom, coord, spin, atype, cell, nghost,
nlist, ago, fparam, aparam, energy, force, force_mag,
virial, atomic_energy, atomic_virial);
}

template <>
inline void _DP_DeepPotComputeNListSP<float>(DP_DeepSpin *dp,
const int nframes,
const int natom,
const float *coord,
const float *spin,
const int *atype,
const float *cell,
const int nghost,
const DP_Nlist *nlist,
const int ago,
const float *fparam,
const float *aparam,
double *energy,
float *force,
float *force_mag,
float *virial,
float *atomic_energy,
float *atomic_virial) {
DP_DeepSpinComputeNListf2(dp, nframes, natom, coord, spin, atype, cell,
nghost, nlist, ago, fparam, aparam, energy, force,
force_mag, virial, atomic_energy, atomic_virial);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add parameter validation for spin vector

The function should validate that the spin vector has the correct dimensions (nframes * natoms * 3) before computation to prevent buffer overflows.

+    // Validate spin dimensions
+    if (spin == nullptr) {
+        throw deepmd::hpp::deepmd_exception("spin vector cannot be null");
+    }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +16 to +18
// 1e-10 cannot pass; unclear bug or not
#undef EPSILON
#define EPSILON (std::is_same<VALUETYPE, double>::value ? 1e-7 : 1e-1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Investigate the reason for relaxed EPSILON tolerance

The EPSILON value is relaxed to 1e-7 for double precision and 1e-1 for single precision due to an unclear bug (// 1e-10 cannot pass; unclear bug or not). Adjusting the tolerance may mask underlying numerical issues or instabilities. It's recommended to investigate and resolve the root cause rather than relaxing the tolerance.

Would you like assistance in diagnosing this issue or refining the test cases?

Comment on lines 1642 to 1645
const char* DP_DeepBaseModelGetTypeMap(DP_DeepBaseModel* dpbase) {
std::string type_map;
dp->dp.get_type_map(type_map);
dpbase->dpbase.get_type_map(type_map);
return string_to_char(type_map);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Document Ownership of Returned C Strings to Prevent Memory Leaks

The functions DP_DeepBaseModelGetTypeMap, DP_DeepBaseModelCheckOK, and DP_DeepBaseModelDeviCheckOK return const char* pointers that are dynamically allocated using new[] in the string_to_char function. Since the caller is responsible for freeing this memory using DP_DeleteChar, it's important to document this ownership explicitly to prevent memory leaks. Consider updating the function comments or documentation to make this requirement clear to users.

Also applies to: 1672-1673, 1931-1932


vector<double> dspin(nall * 3, 0.);
vector<double> dfm(nall * 3, 0.);
double **sp = atom->sp;

Check notice

Code scanning / CodeQL

Unused local variable

Variable sp is not used.
vector<double> dspin(nall * 3, 0.);
vector<double> dfm(nall * 3, 0.);
double **sp = atom->sp;
double **fm = atom->fm;

Check notice

Code scanning / CodeQL

Unused local variable

Variable fm is not used.
type_idx_map.clear();
type_names.clear();
while (iarg < narg) {
std::string type_name = arg[iarg];

Check notice

Code scanning / CodeQL

Declaration hides variable

Variable type_name hides another variable of the same name (on [line 420](1)).
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Outside diff range and nitpick comments (19)
source/lmp/pair_deepmd.h (2)

39-42: Consider documenting the CommBrickDeepMD class purpose.

The friendship relationship with PairDeepMD suggests this class plays a crucial role in communication. Adding documentation about its purpose and the necessity of the friendship relationship would improve maintainability.


Line range hint 43-61: Document spin model integration.

Given that this PR aims to enhance LAMMPS support for spin models, please add documentation explaining:

  1. How this class interacts with spin calculations
  2. The role of DeepPot and DeepPotModelDevi in spin model support
source/lmp/pair_deepspin.h (3)

2-4: Document the LAMMPS version requirement.

The version check is crucial for compatibility, but it's not clear what format or minimum version is required. Consider adding a comment explaining the expected format and minimum supported version.

Add a comment above the check:

 // SPDX-License-Identifier: LGPL-3.0-or-later
+// LAMMPS_VERSION_NUMBER should be defined as YYYYMMDD (e.g., 20220101)
+// Minimum supported version: <specify_version>
 #ifndef LAMMPS_VERSION_NUMBER

15-29: Consider modernizing the build configuration handling.

The current preprocessor-based include path selection could be simplified using modern CMake configuration. This would make the code more maintainable and reduce preprocessor complexity.

Consider:

  1. Using CMake's configure_file to generate a header with proper paths
  2. Using target_include_directories to handle include paths
  3. Moving the build configuration logic to CMake

This would eliminate the need for complex preprocessor directives in the source code.


43-52: Add class and method documentation.

The PairDeepSpin class and its methods lack documentation explaining their purpose, parameters, and usage. This is particularly important for public API methods.

Add Doxygen-style documentation:

/**
 * @brief Implements deep learning-based spin interactions for LAMMPS.
 * 
 * This class extends PairDeepBaseModel to provide spin-specific functionality
 * for molecular dynamics simulations.
 */
class PairDeepSpin : public PairDeepBaseModel {
public:
    /**
     * @brief Constructs a new PairDeepSpin object.
     * @param lmp Pointer to the LAMMPS instance
     */
    PairDeepSpin(LAMMPS* lmp);
    // ... document other methods similarly
source/lmp/pair_base.h (4)

6-7: Align header guard with file name.

The header guard LMP_PAIR_NNP_BASE_H doesn't match the file name pair_base.h. Consider using LMP_PAIR_BASE_H for consistency.

-#ifndef LMP_PAIR_NNP_BASE_H
-#define LMP_PAIR_NNP_BASE_H
+#ifndef LMP_PAIR_BASE_H
+#define LMP_PAIR_BASE_H

10-24: Consider simplifying the conditional compilation structure.

The nested conditional compilation makes the code harder to read and maintain. Consider extracting the include path logic into a separate header or using a more modern configuration system.

+// TODO: Consider using CMake configure_file or similar to handle include paths
 #ifdef DP_USE_CXX_API
-#ifdef LMPPLUGIN
-#include "DeepBaseModel.h"
-#else
-#include "deepmd/DeepBaseModel.h"
-#endif
+#include DEEPMD_BASE_MODEL_HEADER
 namespace deepmd_compat = deepmd;
 #else
-#ifdef LMPPLUGIN
-#include "deepmd.hpp"
-#else
-#include "deepmd/deepmd.hpp"
-#endif
+#include DEEPMD_HPP_HEADER
 namespace deepmd_compat = deepmd::hpp;
 #endif

31-50: Add documentation for public methods and improve parameter names.

The public interface would benefit from:

  1. Documentation comments explaining the purpose and behavior of each method
  2. More descriptive parameter names in method declarations

Example improvement:

/**
 * @brief Prints a summary of the model's configuration and state
 * @param prefix String to prepend to each line of output
 */
void print_summary(const std::string prefix) const;

106-113: Add documentation for utility functions.

The utility functions would benefit from documentation explaining their purpose, parameters, and return values.

Example improvement:

/**
 * @brief Uniformly distributes atomic parameters across local atoms
 * @param daparam Output vector of distributed parameters
 * @param aparam Input vector of parameters to distribute
 * @param nlocal Number of local atoms
 */
void make_uniform_aparam(std::vector<double>& daparam,
                        const std::vector<double>& aparam,
                        const int& nlocal);
source/api_c/include/deepmd.hpp (3)

98-156: Add documentation for spin computation functions

The newly added template functions _DP_DeepPotComputeSP and their specializations lack documentation. Add function documentation that describes:

  • Purpose of the functions
  • Parameters and their expected dimensions
  • Return values
  • Example usage

1423-1722: Consider refactoring to reduce code duplication

The compute methods contain duplicated reshape logic. Consider extracting the common reshape operations into a helper method to improve maintainability.

Create a helper method like:

template <typename VALUETYPE>
void reshape_arrays(std::vector<VALUETYPE>& dest, 
                   const std::vector<VALUETYPE>& src,
                   const size_t nframes,
                   const size_t natoms,
                   const size_t stride) {
    dest.resize(nframes * natoms * stride);
    for (size_t i = 0; i < nframes * natoms * stride; ++i) {
        dest[i] = src[i];
    }
}

Line range hint 2368-2595: Remove unused variable and refactor reshape logic

The class implementation has two issues that should be addressed:

  1. The variable 'ndof' is declared but never used (as flagged by static analysis)

  2. The reshape logic is duplicated across compute methods

  3. Remove the unused variable:

-   unsigned ndof = avg.size();
    unsigned nloc = std.size();
  1. Consider extracting the reshape logic into a helper method similar to the suggestion for DeepSpin class.
source/lmp/pair_base.cpp (3)

54-99: Consider using MPI_Comm_split_type for node-aware communicator creation.

Instead of manually comparing host names to create a node-aware communicator, consider using MPI_Comm_split_type with MPI_COMM_TYPE_SHARED. This is a more efficient and portable approach.

-  char host_name[MPI_MAX_PROCESSOR_NAME];
-  memset(host_name, '\0', sizeof(char) * MPI_MAX_PROCESSOR_NAME);
-  char(*host_names)[MPI_MAX_PROCESSOR_NAME];
-  int n, namelen, color, rank, nprocs, myrank;
-  size_t bytes;
+  int rank, nprocs, myrank;
   MPI_Comm nodeComm;

   MPI_Comm_rank(MPI_COMM_WORLD, &rank);
   MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
-  MPI_Get_processor_name(host_name, &namelen);
-
-  bytes = nprocs * sizeof(char[MPI_MAX_PROCESSOR_NAME]);
-  host_names = (char(*)[MPI_MAX_PROCESSOR_NAME])malloc(bytes);
-  for (int ii = 0; ii < nprocs; ii++) {
-    memset(host_names[ii], '\0', sizeof(char) * MPI_MAX_PROCESSOR_NAME);
-  }
-
-  strcpy(host_names[rank], host_name);
-
-  for (n = 0; n < nprocs; n++) {
-    MPI_Bcast(&(host_names[n]), MPI_MAX_PROCESSOR_NAME, MPI_CHAR, n,
-              MPI_COMM_WORLD);
-  }
-  qsort(host_names, nprocs, sizeof(char[MPI_MAX_PROCESSOR_NAME]), stringCmp);
-
-  color = 0;
-  for (n = 0; n < nprocs - 1; n++) {
-    if (strcmp(host_name, host_names[n]) == 0) {
-      break;
-    }
-    if (strcmp(host_names[n], host_names[n + 1])) {
-      color++;
-    }
-  }
-
-  MPI_Comm_split(MPI_COMM_WORLD, color, 0, &nodeComm);
+  MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &nodeComm);
   MPI_Comm_rank(nodeComm, &myrank);

   MPI_Barrier(MPI_COMM_WORLD);
   int looprank = myrank;
-  free(host_names);
   return looprank;

408-412: Consider implementing restart functionality.

The read_restart and write_restart functions are currently empty. Consider implementing the necessary functionality to properly handle restarting simulations with the deepmd pair style.


438-455: Improve warning message formatting.

The warning message in the init_one function could be improved for better readability. Consider using snprintf instead of sprintf to avoid potential buffer overflow and use a more structured format for the message.

-  char warning_msg[1024];
-  sprintf(warning_msg,
-          "Interaction between types %d and %d is set with deepmd, but will "
-          "be ignored.\n Deepmd model has only %d types, it only computes "
-          "the mulitbody interaction of types: 1-%d.",
-          i, j, numb_types, numb_types);
+  char warning_msg[1024];
+  snprintf(warning_msg, sizeof(warning_msg),
+           "Interaction between types %d and %d is set with deepmd, but will be ignored.\n"
+           "Deepmd model has only %d types, it only computes the multibody interaction of types: 1-%d.",
+           i, j, numb_types, numb_types);
   error->warning(FLERR, warning_msg);
source/lmp/pair_deepspin.cpp (4)

620-625: Remove commented-out code to improve readability

The lines contain commented-out code related to atomic virial computation. If this code is no longer needed, consider removing it to enhance code readability and maintainability.


693-698: Remove commented-out code to improve readability

These lines include commented-out code for atomic virial updates. Removing unused code can help keep the codebase clean and understandable.


885-886: Clean up unnecessary commented-out code

The malloc_trim(0); function call is commented out. If it's not intended for future use or debugging, consider removing it to maintain code cleanliness.


887-887: Remove unused or commented-out code

The call to malloc_trim(0); is commented out. If memory trimming is no longer required or applicable, consider removing this line to keep the code clean.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2c4ca0d and 7eab6cc.

📒 Files selected for processing (7)
  • source/api_c/include/deepmd.hpp (21 hunks)
  • source/lmp/pair_base.cpp (1 hunks)
  • source/lmp/pair_base.h (1 hunks)
  • source/lmp/pair_deepmd.cpp (6 hunks)
  • source/lmp/pair_deepmd.h (1 hunks)
  • source/lmp/pair_deepspin.cpp (1 hunks)
  • source/lmp/pair_deepspin.h (1 hunks)
🔇 Additional comments (24)
source/lmp/pair_deepmd.h (2)

Line range hint 1-36: LGTM: Well-organized header structure.

The conditional compilation directives and header organization properly handle different build configurations while maintaining clean namespace separation.


43-56: Verify the base class functionality.

The refactoring to inherit from PairDeepBaseModel looks good and reduces code duplication. However, we should verify that all required functionality is properly inherited.

✅ Verification successful

Base class functionality verified and properly implemented

The refactoring is correct. The PairDeepBaseModel base class in pair_base.h contains all the previously removed methods from PairDeepMD:

  • extract(const char *, int &)
  • init_style()
  • write_restart(FILE *)
  • read_restart(FILE *)
  • init_one(int i, int j)

The git history confirms these methods were moved from PairDeepMD to the base class, improving code organization while maintaining functionality. The inheritance hierarchy and method overrides are properly structured.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that PairDeepBaseModel contains all necessary methods
# that were previously in PairDeepMD

# Search for the removed methods in PairDeepBaseModel
ast-grep --pattern 'class PairDeepBaseModel {
  $$$
  extract($$$) {
    $$$
  }
  $$$
}'

ast-grep --pattern 'class PairDeepBaseModel {
  $$$
  init_style($$$) {
    $$$
  }
  $$$
}'

Length of output: 186


Script:

#!/bin/bash
# Let's first find the PairDeepBaseModel definition
rg -l "class PairDeepBaseModel" --type cpp

# Then examine its contents
rg "class PairDeepBaseModel" -A 30 --type cpp

# Also check for any virtual methods in the base class
ast-grep --pattern 'class PairDeepBaseModel {
  $$$
  virtual $_ $_($$$) $_; 
  $$$
}'

# Let's also check the git history to see what methods were removed
git log -p source/lmp/pair_deepmd.h | rg -A 5 -B 5 "^[-+].*\b(extract|init_style)\b"

Length of output: 3187

source/lmp/pair_deepspin.h (1)

56-56: Consider thread safety for force magnitude storage.

The all_force_mag vector might be accessed from multiple threads during computation. Ensure proper synchronization or use thread-local storage if needed.

source/lmp/pair_base.h (2)

61-61: Verify spin model implementation details.

The spin-related additions (numb_types_spin, spin_norm, index mapping) need verification:

  1. Are the spin norms properly initialized and maintained?
  2. Is the index mapping robust enough for all LAMMPS operations?
#!/bin/bash
# Search for spin norm initialization and usage
rg -A 5 "spin_norm" --type cpp

# Search for index mapping implementation
rg -A 5 "new_idx_map|old_idx_map" --type cpp

Also applies to: 77-77, 78-80


53-85: Improve organization and documentation of member variables.

Consider grouping related members together and adding documentation for each group. For example:

  • Model configuration (cutoff, numb_types, etc.)
  • Output settings (out_freq, out_file, etc.)
  • Spin-related state (numb_types_spin, spin_norm)

Additionally, verify that the spin-related variables align with the LAMMPS spin model requirements.

source/lmp/pair_deepmd.cpp (2)

87-90: LGTM! Constructor and destructor changes look good.

The changes simplify the implementation by properly utilizing inheritance and removing spin-related initialization.

Also applies to: 93-94


438-470: LGTM! Type mapping improvements look good.

The changes improve type handling by:

  • Adding support for NULL type as ghost type
  • Providing clearer error messages
  • Properly handling type mapping and validation
source/api_c/include/deepmd.hpp (1)

839-947: LGTM! Well-structured base model changes

The additions to DeepBaseModel class are well-designed with:

  • Clear separation of concerns
  • Consistent error handling
  • Complete documentation
source/lmp/pair_base.cpp (13)

38-52: LGTM!

The stringCmp function is implemented correctly. It compares two strings lexicographically by iterating over the characters and returning the difference between the first non-matching characters. If the strings are equal, it returns 0.


124-131: LGTM!

The get_file_content overload for a vector of file paths is implemented correctly. It iterates over the input vector, calls the single-file overload for each path, and returns a vector of file contents.


133-160: LGTM!

The make_fparam_from_compute function is implemented correctly. It retrieves the compute object based on the provided ID, checks if it exists, resizes the fparam vector, and populates it with the scalar or vector values from the compute, depending on the dimension.


162-189: LGTM!

The make_aparam_from_compute function is implemented correctly. It retrieves the compute object based on the provided ID, checks if it exists, resizes the aparam vector based on the local atom count and dimension, and populates it with the per-atom vector or array values from the compute.


192-229: LGTM!

The make_ttm_fparam function is implemented correctly. It retrieves the TTM fix object, checks if it exists, resizes the fparam vector, and calculates the average electron temperature over the effective nodes. The average temperature is stored in fparam[0].


278-284: LGTM!

The cum_sum function is implemented correctly. It calculates the cumulative sum of the values in the vec map and stores the results in the sum map. The cumulative sum at index i is the sum of values from index 0 to i-1 in the input vector.


347-370: LGTM!

The print_summary function is implemented correctly. It captures the output of cout to a string stream, prints the summary information about the deepmd-kit and LAMMPS module, and then restores the original cout buffer. The summary string is logged using LAMMPS's utils::logmesg function.


380-406: LGTM!

The allocate function is implemented correctly. It allocates memory for the setflag, cutsq, and scale arrays based on the number of atom types. It initializes the arrays with default values and sets the appropriate flags and scales for the defined number of types.


414-436: LGTM!

The init_style function is implemented correctly. It adds a request for full neighbor lists and allocates memory for communication buffers if out_each is set to 1. The memory is allocated based on the total number of atoms and the maximum buffer size.


457-467: LGTM!

The extract function is implemented correctly. It returns a pointer to the cutoff variable if the requested string is "cut_coul" and a pointer to the scale array if the requested string is "scale". The dim parameter is set accordingly to indicate the dimension of the returned data.


469-489: LGTM!

The ana_st function is implemented correctly. It calculates the maximum, minimum, and sum of the values in the vec vector, considering only the first nloc elements. If nloc is 0, the function returns without modifying the input parameters.


491-501: LGTM!

The make_uniform_aparam function is implemented correctly. It creates a uniform daparam vector by replicating the values from the aparam vector for each local atom. The resulting daparam vector has a size of dim_aparam * nlocal, where dim_aparam is the size of aparam and nlocal is the number of local atoms.


286-345: Verify compatibility with other unit styles.

The constructor checks for compatibility with the "lj" unit style and throws an error if it is used. However, it does not verify compatibility with other unit styles. Consider adding checks for other supported unit styles or documenting the compatible unit styles.

source/lmp/pair_deepspin.cpp (3)

511-515: Replace std::cout with proper error handling

Using std::cout for error messages is inconsistent with LAMMPS' error handling mechanisms. Replace std::cout with error->all or error->one to ensure consistent error reporting.


521-545: Verify the handling of ghost atoms in coordinate computations

In the coordinate transformation loop, ghost atoms are included without explicit checks. Ensure that the handling of ghost atoms in coordinate computations is intentional and does not introduce unexpected behavior.

Run the following script to check the indices of ghost atoms:

✅ Verification successful

Let me analyze the results. The code shows that:

  1. nall is correctly defined as nlocal + nghost
  2. Ghost atoms are conditionally included based on do_ghost flag
  3. The deep potential computation (deep_spin.compute) handles both local and ghost atoms through the InputNlist structure
  4. The coordinate transformation is consistently applied to all atoms (both local and ghost) which is necessary for proper force calculations in molecular dynamics

Given this evidence, I can generate the final response:

Ghost atom handling in coordinate computations is correctly implemented

The inclusion of ghost atoms in coordinate computations is intentional and necessary for proper force calculations. The code properly initializes nall as the sum of local and ghost atoms, and the coordinate transformation is consistently applied within the deep potential computation framework through InputNlist.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that ghost atoms are properly handled in coordinate computations.

# Test: List indices of ghost atoms and ensure they are correctly processed.
ast-grep --pattern $'for (int ii = 0; ii < nall; ++ii) {
  $$$
}' source/lmp/pair_deepspin.cpp

# Check where nall is defined as nlocal + nghost.
rg 'int nall = nlocal \+ nghost;' source/lmp/pair_deepspin.cpp

# Verify if there are any conditions that differentiate between local and ghost atoms.
rg 'if \(do_ghost\)' source/lmp/pair_deepspin.cpp -A 10

Length of output: 6861


876-882: ⚠️ Potential issue

Ensure sp[ii][3] is non-zero before division to prevent runtime errors

In the force computation, the code divides by (hbar / sp[ii][3]). If sp[ii][3] is zero, this will result in a division by zero error.

Apply this diff to add a check before the division:

 for (int ii = 0; ii < nall; ++ii) {
   for (int dd = 0; dd < 3; ++dd) {
     f[ii][dd] += scale[1][1] * dforce[3 * ii + dd] * force_unit_cvt_factor;
+    if (sp[ii][3] == 0.0) {
+      error->one(FLERR, "Spin magnitude sp[ii][3] is zero; division by zero detected in force computation.");
+    }
     fm[ii][dd] += scale[1][1] * dforce_mag[3 * ii + dd] / (hbar / sp[ii][3]) *
                   force_unit_cvt_factor;
   }
 }

Likely invalid or redundant comment.

Comment on lines +504 to +506
std::cout << "Pair style 'deepmd' does not support spin atoms, please use "
"pair style 'deepspin' instead."
<< std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use LAMMPS error system instead of cout for error messages.

The code uses cout to print error messages about spin atoms in multiple places. This should be replaced with LAMMPS error system for consistent error handling.

Apply this diff to fix all instances:

-    std::cout << "Pair style 'deepmd' does not support spin atoms, please use "
-                 "pair style 'deepspin' instead."
-              << std::endl;
+    error->all(FLERR, "Pair style 'deepmd' does not support spin atoms. "
+               "Please use pair style 'deepspin' instead.");

Also applies to: 874-877, 896-899

Comment on lines +873 to +883
if (atom->sp_flag) {
std::cout << "Pair style 'deepmd' does not support spin atoms, please use "
"pair style 'deepspin' instead."
<< std::endl;
} else {
for (i = first; i < last; i++) {
for (int dd = 0; dd < numb_models; ++dd) {
buf[m++] = all_force[dd][3 * i + 0];
buf[m++] = all_force[dd][3 * i + 1];
buf[m++] = all_force[dd][3 * i + 2];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Check for spin atoms early in communication methods.

The error for spin atoms should be checked before allocating memory or performing any operations.

Apply this diff to improve error handling:

int PairDeepMD::pack_reverse_comm(int n, int first, double *buf) {
+  if (atom->sp_flag) {
+    error->all(FLERR, "Pair style 'deepmd' does not support spin atoms. "
+               "Please use pair style 'deepspin' instead.");
+  }
  int i, m, last;
  m = 0;
  last = first + n;
-  if (atom->sp_flag) {
-    std::cout << "Pair style 'deepmd' does not support spin atoms, please use "
-                 "pair style 'deepspin' instead."
-              << std::endl;
-  } else {
    for (i = first; i < last; i++) {
      for (int dd = 0; dd < numb_models; ++dd) {
        buf[m++] = all_force[dd][3 * i + 0];
        buf[m++] = all_force[dd][3 * i + 1];
        buf[m++] = all_force[dd][3 * i + 2];
      }
    }
-  }
  return m;
}

Similar changes should be applied to unpack_reverse_comm.

Also applies to: 895-907

Comment on lines +1500 to +1539
void compute(
ENERGYVTYPE &ener,
std::vector<VALUETYPE> &force,
std::vector<VALUETYPE> &force_mag,
std::vector<VALUETYPE> &virial,
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
assert(nframes * natoms * 3 == coord.size());
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, natoms, fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes, natoms * daparam, aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;

_DP_DeepPotComputeSP<VALUETYPE>(dp, nframes, natoms, coord_, spin_, atype_,
box_, fparam__, aparam__, ener_, force_,
force_mag_, virial_, nullptr, nullptr);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add validation for spin vector dimensions

The compute methods should validate that the spin vector has the correct dimensions (nframes * natoms * 3) to prevent buffer overflows.

Add validation after the existing coordinate validation:

    assert(nframes * natoms * 3 == coord.size());
+   assert(nframes * natoms * 3 == spin.size());  // Validate spin dimensions
    if (!box.empty()) {
      assert(box.size() == nframes * 9);
    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void compute(
ENERGYVTYPE &ener,
std::vector<VALUETYPE> &force,
std::vector<VALUETYPE> &force_mag,
std::vector<VALUETYPE> &virial,
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
assert(nframes * natoms * 3 == coord.size());
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, natoms, fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes, natoms * daparam, aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;
_DP_DeepPotComputeSP<VALUETYPE>(dp, nframes, natoms, coord_, spin_, atype_,
box_, fparam__, aparam__, ener_, force_,
force_mag_, virial_, nullptr, nullptr);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
};
void compute(
ENERGYVTYPE &ener,
std::vector<VALUETYPE> &force,
std::vector<VALUETYPE> &force_mag,
std::vector<VALUETYPE> &virial,
const std::vector<VALUETYPE> &coord,
const std::vector<VALUETYPE> &spin,
const std::vector<int> &atype,
const std::vector<VALUETYPE> &box,
const std::vector<VALUETYPE> &fparam = std::vector<VALUETYPE>(),
const std::vector<VALUETYPE> &aparam = std::vector<VALUETYPE>()) {
unsigned int natoms = atype.size();
unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
assert(nframes * natoms * 3 == coord.size());
assert(nframes * natoms * 3 == spin.size()); // Validate spin dimensions
if (!box.empty()) {
assert(box.size() == nframes * 9);
}
const VALUETYPE *coord_ = &coord[0];
const VALUETYPE *spin_ = &spin[0];
const VALUETYPE *box_ = !box.empty() ? &box[0] : nullptr;
const int *atype_ = &atype[0];
double *ener_ = _DP_Get_Energy_Pointer(ener, nframes);
force.resize(static_cast<size_t>(nframes) * natoms * 3);
force_mag.resize(static_cast<size_t>(nframes) * natoms * 3);
virial.resize(static_cast<size_t>(nframes) * 9);
VALUETYPE *force_ = &force[0];
VALUETYPE *force_mag_ = &force_mag[0];
VALUETYPE *virial_ = &virial[0];
std::vector<VALUETYPE> fparam_, aparam_;
validate_fparam_aparam(nframes, natoms, fparam, aparam);
tile_fparam_aparam(fparam_, nframes, dfparam, fparam);
tile_fparam_aparam(aparam_, nframes, natoms * daparam, aparam);
const VALUETYPE *fparam__ = !fparam_.empty() ? &fparam_[0] : nullptr;
const VALUETYPE *aparam__ = !aparam_.empty() ? &aparam_[0] : nullptr;
_DP_DeepPotComputeSP<VALUETYPE>(dp, nframes, natoms, coord_, spin_, atype_,
box_, fparam__, aparam__, ener_, force_,
force_mag_, virial_, nullptr, nullptr);
DP_CHECK_OK(DP_DeepBaseModelCheckOK, (DP_DeepBaseModel *)dp);
};

Comment on lines +101 to +122
std::string PairDeepBaseModel::get_file_content(const std::string &model) {
int myrank = 0, root = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
int nchar = 0;
std::string file_content;
if (myrank == root) {
deepmd_compat::read_file_to_string(model, file_content);
nchar = file_content.size();
}
MPI_Bcast(&nchar, 1, MPI_INT, root, MPI_COMM_WORLD);
char *buff = (char *)malloc(sizeof(char) * nchar);
if (myrank == root) {
memcpy(buff, file_content.c_str(), sizeof(char) * nchar);
}
MPI_Bcast(buff, nchar, MPI_CHAR, root, MPI_COMM_WORLD);
file_content.resize(nchar);
for (unsigned ii = 0; ii < nchar; ++ii) {
file_content[ii] = buff[ii];
}
free(buff);
return file_content;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure allocated memory in get_file_content() is properly deallocated.

The character buffer buff is allocated using malloc but is not freed in all code paths. If MPI_Bcast fails, the allocated memory will be leaked. Use RAII or ensure proper cleanup in all scenarios.

   char *buff = (char *)malloc(sizeof(char) * nchar);
   if (myrank == root) {
     memcpy(buff, file_content.c_str(), sizeof(char) * nchar);
   }
-  MPI_Bcast(buff, nchar, MPI_CHAR, root, MPI_COMM_WORLD);
+  if (MPI_Bcast(buff, nchar, MPI_CHAR, root, MPI_COMM_WORLD) != MPI_SUCCESS) {
+    free(buff);
+    // Handle the error, e.g., throw an exception or return an empty string
+  }
   file_content.resize(nchar);
   for (unsigned ii = 0; ii < nchar; ++ii) {
     file_content[ii] = buff[ii];
   }
   free(buff);

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +233 to +275
void PairDeepBaseModel::make_ttm_aparam(vector<double> &daparam) {
assert(do_ttm);
// get ttm_fix
const FixTTMDP *ttm_fix = NULL;
for (int ii = 0; ii < modify->nfix; ii++) {
if (string(modify->fix[ii]->id) == ttm_fix_id) {
ttm_fix = dynamic_cast<FixTTMDP *>(modify->fix[ii]);
}
}
if (!ttm_fix) {
error->all(FLERR, "fix ttm id is not found: " + ttm_fix_id);
}
// modify
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
vector<int> nnodes = ttm_fix->get_nodes();
int nxnodes = nnodes[0];
int nynodes = nnodes[1];
int nznodes = nnodes[2];
double ***const T_electron = ttm_fix->get_T_electron();
double dx = domain->xprd / nxnodes;
double dy = domain->yprd / nynodes;
double dz = domain->zprd / nynodes;
// resize daparam
daparam.resize(nlocal);
// loop over atoms to assign aparam
for (int ii = 0; ii < nlocal; ii++) {
if (mask[ii] & ttm_fix->groupbit) {
double xscale = (x[ii][0] - domain->boxlo[0]) / domain->xprd;
double yscale = (x[ii][1] - domain->boxlo[1]) / domain->yprd;
double zscale = (x[ii][2] - domain->boxlo[2]) / domain->zprd;
int ixnode = static_cast<int>(xscale * nxnodes);
int iynode = static_cast<int>(yscale * nynodes);
int iznode = static_cast<int>(zscale * nznodes);
// https://stackoverflow.com/a/1907585/9567349
ixnode = ((ixnode % nxnodes) + nxnodes) % nxnodes;
iynode = ((iynode % nynodes) + nynodes) % nynodes;
iznode = ((iznode % nznodes) + nznodes) % nznodes;
daparam[ii] = T_electron[ixnode][iynode][iznode];
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure array indices are within bounds.

When calculating the node indices (ixnode, iynode, iznode) based on the atom positions, ensure that the indices are within the valid range of the T_electron array dimensions. Consider adding boundary checks or using a different mapping scheme to avoid out-of-bounds access.

   int ixnode = static_cast<int>(xscale * nxnodes);
   int iynode = static_cast<int>(yscale * nynodes);
   int iznode = static_cast<int>(zscale * nznodes);
+  ixnode = std::max(0, std::min(ixnode, nxnodes - 1));
+  iynode = std::max(0, std::min(iynode, nynodes - 1));
+  iznode = std::max(0, std::min(iznode, nznodes - 1));
   daparam[ii] = T_electron[ixnode][iynode][iznode];

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +300 to +324
fp.open(out_file);
fp << scientific;
if (!atom->sp_flag) {
fp << "#" << setw(12 - 1) << "step" << setw(18 + 1) << "max_devi_v"
<< setw(18 + 1) << "min_devi_v" << setw(18 + 1) << "avg_devi_v"
<< setw(18 + 1) << "max_devi_f" << setw(18 + 1) << "min_devi_f"
<< setw(18 + 1) << "avg_devi_f";
if (out_each) {
// at this time, we don't know how many atoms
fp << setw(18 + 1) << "atm_devi_f(N)";
}
fp << endl;
} else {
fp << "#" << setw(12 - 1) << "step" << setw(18 + 1) << "max_devi_v"
<< setw(18 + 1) << "min_devi_v" << setw(18 + 1) << "avg_devi_v"
<< setw(18 + 1) << "max_devi_fr" << setw(18 + 1) << "min_devi_fr"
<< setw(18 + 1) << "avg_devi_fr" << setw(18 + 1) << "max_devi_fm"
<< setw(18 + 1) << "min_devi_fm" << setw(18 + 1) << "avg_devi_fm"
<< endl;
}
} else {
fp.open(out_file, std::ofstream::out | std::ofstream::app);
fp << scientific;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error checking after opening the output file

The code opens the output file fp without verifying if the file was successfully opened. Failing to check the file stream can lead to unexpected behavior if the file cannot be opened due to issues such as incorrect file paths or insufficient permissions.

Apply this diff to add error checking:

   if (!is_restart) {
     fp.open(out_file);
+    if (!fp.is_open()) {
+      error->one(FLERR, ("Failed to open output file: " + out_file).c_str());
+    }
     fp << scientific;
     if (!atom->sp_flag) {
       fp << "#" << setw(12 - 1) << "step" << setw(18 + 1) << "max_devi_v"
          << setw(18 + 1) << "min_devi_v" << setw(18 + 1) << "avg_devi_v"
          << setw(18 + 1) << "max_devi_f" << setw(18 + 1) << "min_devi_f"
          << setw(18 + 1) << "avg_devi_f";
       if (out_each) {
         // at this time, we don't know how many atoms
         fp << setw(18 + 1) << "atm_devi_f(N)";
       }
       fp << endl;
     } else {
       fp << "#" << setw(12 - 1) << "step" << setw(18 + 1) << "max_devi_v"
          << setw(18 + 1) << "min_devi_v" << setw(18 + 1) << "avg_devi_v"
          << setw(18 + 1) << "max_devi_fr" << setw(18 + 1) << "min_devi_fr"
          << setw(18 + 1) << "avg_devi_fr" << setw(18 + 1) << "max_devi_fm"
          << setw(18 + 1) << "min_devi_fm" << setw(18 + 1) << "avg_devi_fm"
          << endl;
     }
   } else {
     fp.open(out_file, std::ofstream::out | std::ofstream::app);
+    if (!fp.is_open()) {
+      error->one(FLERR, ("Failed to open output file: " + out_file).c_str());
+    }
     fp << scientific;
   }

Comment on lines +275 to +279
spin_norm.resize(numb_types_spin);
for (int ii = 0; ii < numb_types_spin; ++ii) {
spin_norm[ii] = atof(arg[iarg + ii + 1]);
}
iarg += numb_types_spin + 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add validation for spin_norm values to prevent division by zero

The spin_norm array is populated from user input without validation. If any of these values are zero, it could lead to division by zero errors in subsequent calculations involving sp[ii][3].

Apply this diff to add validation:

 else if (string(arg[iarg]) == string("spin_norm")) {
   spin_norm.resize(numb_types_spin);
   for (int ii = 0; ii < numb_types_spin; ++ii) {
+    if (atof(arg[iarg + ii + 1]) == 0.0) {
+      error->all(FLERR, "spin_norm values must be non-zero to prevent division by zero");
+    }
     spin_norm[ii] = atof(arg[iarg + ii + 1]);
   }
   iarg += numb_types_spin + 1;
 }

Committable suggestion skipped: line range outside the PR's diff.


vector<double> dspin(nall * 3, 0.);
vector<double> dfm(nall * 3, 0.);
double **sp = atom->sp;

Check notice

Code scanning / CodeQL

Unused local variable Note

Variable sp is not used.
vector<double> dspin(nall * 3, 0.);
vector<double> dfm(nall * 3, 0.);
double **sp = atom->sp;
double **fm = atom->fm;

Check notice

Code scanning / CodeQL

Unused local variable Note

Variable fm is not used.
make_fparam_from_compute(fparam);
}

// int ago = numb_models > 1 ? 0 : neighbor->ago;

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.
Comment on lines +610 to +615
// vatom[ii][0] += 1.0 * dvatom[9*ii+0];
// vatom[ii][1] += 1.0 * dvatom[9*ii+4];
// vatom[ii][2] += 1.0 * dvatom[9*ii+8];
// vatom[ii][3] += 1.0 * dvatom[9*ii+3];
// vatom[ii][4] += 1.0 * dvatom[9*ii+6];
// vatom[ii][5] += 1.0 * dvatom[9*ii+7];

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.
Comment on lines +662 to +666
// deep_pot_model_devi.compute_avg (dener, all_energy);
// deep_pot_model_devi.compute_avg (dforce, all_force);
// deep_pot_model_devi.compute_avg (dvirial, all_virial);
// deep_pot_model_devi.compute_avg (deatom, all_atom_energy);
// deep_pot_model_devi.compute_avg (dvatom, all_atom_virial);

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.
Comment on lines +682 to +687
// vatom[ii][0] += 1.0 * dvatom[9*ii+0];
// vatom[ii][1] += 1.0 * dvatom[9*ii+4];
// vatom[ii][2] += 1.0 * dvatom[9*ii+8];
// vatom[ii][3] += 1.0 * dvatom[9*ii+3];
// vatom[ii][4] += 1.0 * dvatom[9*ii+6];
// vatom[ii][5] += 1.0 * dvatom[9*ii+7];

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.
type_idx_map.clear();
type_names.clear();
while (iarg < narg) {
std::string type_name = arg[iarg];

Check notice

Code scanning / CodeQL

Declaration hides variable Note

Variable type_name hides another variable of the same name (on
line 834
).
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Outside diff range and nitpick comments (33)
source/lmp/pair_deepspin.h (5)

2-4: Document the LAMMPS version number requirement.

The error message could be more helpful by explaining where and how to define LAMMPS_VERSION_NUMBER. Consider adding a comment explaining the expected format and where this macro should be defined.

 #ifndef LAMMPS_VERSION_NUMBER
+// LAMMPS_VERSION_NUMBER should be defined in your build system
+// Format: YYYYMMDD (e.g., 20240101 for January 1st, 2024)
 #error Please define LAMMPS_VERSION_NUMBER to yyyymmdd
 #endif

15-29: Document build configuration options.

The conditional compilation structure handles different build configurations but lacks documentation explaining when to use each option. Consider adding comments explaining:

  • When to use DP_USE_CXX_API
  • The purpose of LMPPLUGIN
  • The differences between the include paths
+// Build configurations:
+// DP_USE_CXX_API: Enable C++ API (recommended for direct integration)
+// LMPPLUGIN: Use plugin mode for LAMMPS integration
 #ifdef DP_USE_CXX_API
 #ifdef LMPPLUGIN

43-52: Add class and method documentation.

The PairDeepSpin class and its methods lack documentation explaining their purpose, parameters, and usage. Consider adding detailed documentation using a consistent format (e.g., Doxygen).

+/**
+ * @brief LAMMPS pair style for deep learning-based spin interactions
+ * 
+ * Implements pair interactions for spin systems using the DeepMD model.
+ */
 class PairDeepSpin : public PairDeepBaseModel {
  public:
+   /**
+    * @brief Construct a new Pair Deep Spin object
+    * @param lmp LAMMPS instance pointer
+    */
    PairDeepSpin(class LAMMPS *);

59-59: Consider using smart pointers for better memory management.

The raw pointer commdata_ could lead to memory management issues. Consider using std::unique_ptr if ownership semantics are applicable.

-  CommBrickDeepSpin *commdata_;
+  std::unique_ptr<CommBrickDeepSpin> commdata_;

54-56: Document the purpose of protected members.

The protected members deep_spin and deep_spin_model_devi lack documentation explaining their roles and usage within the class.

 protected:
+  /// Main deep learning model for spin interactions
   deepmd_compat::DeepSpin deep_spin;
+  /// Model for deviation analysis in spin calculations
   deepmd_compat::DeepSpinModelDevi deep_spin_model_devi;
+  /// Storage for force magnitudes across all calculations
   std::vector<std::vector<double> > all_force_mag;
source/lmp/pair_base.h (3)

6-7: Align header guard with filename.

The header guard LMP_PAIR_NNP_BASE_H doesn't match the file name pair_base.h. Consider renaming it to LMP_PAIR_BASE_H for consistency.


31-102: Add documentation for class and methods.

The class and its methods lack documentation. Consider adding:

  1. Class-level documentation explaining the purpose and usage
  2. Method documentation describing parameters, return values, and behavior
  3. Examples of typical usage patterns

This is particularly important for public methods like:

  • print_summary
  • get_node_rank
  • cum_sum
  • get_file_content

61-61: Document spin system implementation details.

The spin-related functionality (including numb_types_spin, spin_norm, and index mapping) needs documentation explaining:

  1. The purpose and usage of spin-specific members
  2. The relationship between old and new atom indices
  3. How the spin norm is calculated and used

This will help maintain consistency with the PR's objective of enhancing LAMMPS support for spin models.

Also applies to: 77-80

source/api_cc/include/DeepBaseModel.h (4)

97-99: Add error handling documentation for constructor

The constructor documentation should specify what happens if initialization fails (e.g., invalid model file or GPU rank). Consider adding exception specifications and error handling details.


162-165: Consider using a common assertion helper method

Multiple methods use the same assertion pattern to check inited. Consider creating a protected helper method to centralize this check and provide more detailed error messages.

+protected:
+  void ensure_initialized() const {
+    if (!inited) {
+      throw std::runtime_error("Model not initialized. Call init() first.");
+    }
+  }

Replace assertions with the helper:

-    assert(inited);
+    ensure_initialized();

Also applies to: 171-173, 179-181, 187-189, 195-197, 273-275


278-281: Document thread safety guarantees

The class manages shared resources (dpbases vector of shared pointers). Please document thread safety guarantees and any synchronization requirements for concurrent access.


13-282: Well-structured backend architecture with room for improvement

The class hierarchy provides a solid foundation for different backend implementations with good separation of concerns. Consider the following architectural improvements:

  1. Add a virtual clone() method to support the prototype pattern
  2. Consider using the PIMPL idiom to reduce compilation dependencies
  3. Add version information or capability flags to support future extensions
source/api_cc/include/DeepPotPT.h (1)

Line range hint 77-119: Consider using parameter structs to improve maintainability.

The compute method overloads have extensive parameter lists which could make the code harder to maintain. Consider grouping related parameters into structs, for example:

struct ComputeInputs {
    std::vector<VALUETYPE> coord;
    std::vector<int> atype;
    std::vector<VALUETYPE> box;
    std::vector<VALUETYPE> fparam;
    std::vector<VALUETYPE> aparam;
    bool atomic;
};

struct NeighborListInputs {
    int nghost;
    InputNlist lmp_list;
    int ago;
};

struct ComputeOutputs {
    ENERGYVTYPE& ener;
    std::vector<VALUETYPE>& force;
    std::vector<VALUETYPE>& virial;
    std::vector<VALUETYPE>& atom_energy;
    std::vector<VALUETYPE>& atom_virial;
};

This would make the method signatures more manageable and easier to extend in the future.

source/api_cc/include/DeepSpin.h (4)

11-14: Update class documentation

The class comment incorrectly describes this as "Deep Potential" when it should be "Deep Spin" to accurately reflect its purpose.

-/**
- * @brief Deep Potential.
- **/
+/**
+ * @brief Deep Spin model backend interface.
+ **/

165-168: Fix documentation formatting

The documentation has inconsistent spacing after asterisks in comments. For example, *and should be * and.


440-441: Fix typo in documentation

There's a typo in the documentation: "contrcutor" should be "constructor".

-   * @brief Initialize the DP model deviation contrcutor.
+   * @brief Initialize the DP model deviation constructor.

1-542: Well-structured spin model implementation

The overall architecture follows good design principles:

  • Clear separation of concerns between backend, main implementation, and model deviation
  • Consistent interface design across all classes
  • Proper use of templates for type flexibility
  • Good memory management with shared_ptr
source/api_cc/include/DeepPot.h (2)

14-14: Class hierarchy changes improve architecture

The refactoring of the inheritance structure with:

  • DeepPotBackend (formerly DeepPotBase) inheriting from DeepBaseModelBackend
  • DeepPot inheriting from DeepBaseModel
  • DeepPotModelDevi inheriting from DeepBaseModelDevi

provides a cleaner separation of concerns and better supports the new spin model functionality.

Also applies to: 207-207, 529-529


Line range hint 571-577: Clarify aparam documentation

The documentation for aparam parameter contains redundant information:

* @param[in] aparam The atomic parameter The array can be of size :
* nframes x natoms x dim_aparam.
* natoms x dim_aparam. Then all frames are assumed to be provided with the
*same aparam. dim_aparam. Then all frames and atoms are provided with the
*same aparam.

Consider simplifying to:

* @param[in] aparam The atomic parameter. The array can be of size:
* - nframes x natoms x dim_aparam
* - natoms x dim_aparam (same parameters used for all frames)
* - dim_aparam (same parameters used for all frames and atoms)
source/lmp/pair_deepspin.cpp (2)

90-90: Remove unnecessary comment.

The comment "Constructor body can be empty" is redundant and doesn't provide any meaningful information.

-  // Constructor body can be empty

125-135: Consider using smart pointers or RAII for model initialization.

The vector of models is allocated on the stack but the model initialization could throw exceptions. Consider using smart pointers or RAII pattern to ensure proper cleanup in case of exceptions.

-  vector<string> models;
+  std::vector<std::unique_ptr<std::string>> models;
source/api_c/include/c_api.h (2)

368-396: Improve documentation clarity for spin parameters.

The documentation should clarify:

  1. The units and format of the spin input array
  2. The physical meaning of force_mag output
  3. The relationship between regular force and magnetic force

1047-1066: Add missing documentation blocks.

The following functions are missing documentation blocks:

  • DP_DeepSpinModelDeviComputeNList2
  • DP_DeepSpinModelDeviComputeNListf2

Please add documentation following the established pattern from similar functions, including:

  • Brief description
  • Version information
  • Parameter descriptions
  • Return value description
  • Warnings about array allocation

Also applies to: 1113-1131

source/api_c/include/deepmd.hpp (3)

98-114: Consider reordering parameters for consistency

The parameter ordering in _DP_DeepPotComputeSP places spin between coord and atype, breaking the established pattern where type-related parameters are grouped together. Consider reordering to maintain consistency with other functions:

-                                const FPTYPE *coord,
-                                const FPTYPE *spin, 
-                                const int *atype,
+                                const FPTYPE *coord,
+                                const int *atype,
+                                const FPTYPE *spin,

98-114: Add documentation for spin-related template functions

The newly added template functions lack documentation comments. Add documentation describing:

  • Function purpose
  • Parameter descriptions
  • Return value description
  • Example usage

Line range hint 2431-2497: Add validation and consider refactoring reshape operations

  1. Add validation for spin vector dimensions:
    unsigned int natoms = atype.size();
    unsigned int nframes = 1;
    assert(natoms * 3 == coord.size());
+   assert(natoms * 3 == spin.size());  // Validate spin dimensions
  1. Consider extracting the reshape operations into a helper function to reduce code duplication:
template <typename VALUETYPE>
void reshape_model_devi_arrays(
    std::vector<double>& ener,
    std::vector<std::vector<VALUETYPE>>& force,
    std::vector<std::vector<VALUETYPE>>& force_mag,
    const std::vector<double>& energy_flat,
    const std::vector<VALUETYPE>& force_flat,
    const std::vector<VALUETYPE>& force_mag_flat,
    int numb_models,
    int natoms) {
    // Common reshape logic here
}
source/lmp/pair_deepmd.cpp (6)

371-376: Simplify Communication Reverse Setup

The conditional related to atom->sp_flag may be unnecessary since spin atoms are not supported.

Simplify the code by removing the condition:

-  if (atom->sp_flag) {
-    comm_reverse = numb_models * 3 * 2;
-  } else {
     comm_reverse = numb_models * 3;
-  }

787-825: Consider Removing Spin-Related Comments and Code

The comment // need support for spin atomic force. indicates missing functionality that may no longer be relevant.

Remove the comment and any related code that pertains to spin atomic forces, since spin support is not provided in this class.

-    // need support for spin atomic force.
     vector<double> std_f_all(atom->natoms);
     // Gather std_f and tags
     tagint *tag = atom->tag;
     int nprocs = comm->nprocs;
     // Grow arrays if necessary
     if (atom->natoms > stdf_comm_buff_size) {
       stdf_comm_buff_size = atom->natoms;
       memory->destroy(stdfsend);
       memory->destroy(stdfrecv);
       memory->destroy(tagsend);
       memory->destroy(tagrecv);
       memory->create(stdfsend, stdf_comm_buff_size, "deepmd:stdfsendall");
       memory->create(stdfrecv, stdf_comm_buff_size, "deepmd:stdfrecvall");
       memory->create(tagsend, stdf_comm_buff_size, "deepmd:tagsendall");
       memory->create(tagrecv, stdf_comm_buff_size, "deepmd:tagrecvall");
     }

501-501: Remove Unused Variable sp

The variable sp is declared but not used in the code.

Remove the unused variable to clean up the code.

-  double **sp = atom->sp;

502-502: Remove Unused Variable fm

Similar to the previous comment, the variable fm is declared but not utilized.

Remove the unused variable:

-  double **fm = atom->fm;

556-556: Remove Commented-Out Code

The commented-out code may cause confusion.

Delete the commented line to improve code readability.

-  // int ago = numb_models > 1 ? 0 : neighbor->ago;

834-840: Clarify Error Message for Serial Execution

The error message "Serial version does not support model devi" may be unclear to users.

Improve the error message for clarity:

          error->all(FLERR, "Serial execution does not support model deviation calculations. Please run in parallel to use this feature.");
source/api_c/src/c_api.cc (1)

1872-1904: Document ownership of returned C strings.

The DP_DeepBaseModelGetTypeMap and DP_DeepBaseModelCheckOK functions return const char* pointers that are dynamically allocated using new[] in the string_to_char function. Document that the caller is responsible for freeing this memory using DP_DeleteChar to prevent memory leaks.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2c4ca0d and af09efd.

📒 Files selected for processing (16)
  • source/api_c/include/c_api.h (13 hunks)
  • source/api_c/include/deepmd.hpp (21 hunks)
  • source/api_c/src/c_api.cc (14 hunks)
  • source/api_cc/include/DeepBaseModel.h (1 hunks)
  • source/api_cc/include/DeepPot.h (13 hunks)
  • source/api_cc/include/DeepPotPT.h (3 hunks)
  • source/api_cc/include/DeepPotTF.h (2 hunks)
  • source/api_cc/include/DeepSpin.h (1 hunks)
  • source/api_cc/include/DeepSpinPT.h (1 hunks)
  • source/api_cc/include/DeepSpinTF.h (1 hunks)
  • source/lmp/pair_base.cpp (1 hunks)
  • source/lmp/pair_base.h (1 hunks)
  • source/lmp/pair_deepmd.cpp (6 hunks)
  • source/lmp/pair_deepmd.h (1 hunks)
  • source/lmp/pair_deepspin.cpp (1 hunks)
  • source/lmp/pair_deepspin.h (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • source/api_cc/include/DeepSpinPT.h
  • source/api_cc/include/DeepSpinTF.h
  • source/lmp/pair_deepmd.h
🔇 Additional comments (46)
source/lmp/pair_base.h (1)

37-37: Consider marking base class destructor as virtual.

The destructor is marked with override but the base class Pair destructor might not be virtual. Verify that the base class destructor is virtual to ensure proper cleanup of derived classes.

source/api_cc/include/DeepBaseModel.h (1)

55-55: Verify spin type handling across implementations

The new numb_types_spin() method suggests this is a breaking change that requires all backend implementations to handle spin types. Ensure all derived classes implement this method correctly.

✅ Verification successful

Method numb_types_spin() is properly implemented across the codebase

The pure virtual method numb_types_spin() is correctly implemented by all derived classes:

  • DeepPotTF, DeepPotPT, DeepSpinTF, and DeepSpinPT classes implement it with proper initialization checks
  • DeepBaseModel implements it by delegating to the underlying dpbase
  • Unit tests verify the functionality (e.g., in test_deeppot_a.cc)
  • The method is actively used in LAMMPS integration code for spin-related calculations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for all implementations of numb_types_spin
ast-grep --pattern 'numb_types_spin() {
  $$$
}'

Length of output: 50


Script:

#!/bin/bash
# Let's try a different pattern to find implementations, including const qualifier
ast-grep --pattern 'numb_types_spin() const {
  $$$
}'

# Also search for any files containing numb_types_spin to catch all possible implementations
rg "numb_types_spin" -A 2

Length of output: 9210

source/api_cc/include/DeepPotPT.h (2)

19-19: Good addition of virtual destructor.

Adding the virtual destructor is essential for proper cleanup in the inheritance hierarchy, preventing potential resource leaks when deleting derived class objects through base class pointers.


13-13: Base class change looks good, but verify inheritance chain.

The change from DeepPotBase to DeepPotBackend suggests a good architectural separation for backend-specific implementations.

Let's verify the inheritance chain and related classes:

✅ Verification successful

Base class change is consistent with the codebase architecture.

The verification shows that:

  1. Both DeepPotPT and DeepPotTF now inherit from DeepPotBackend
  2. DeepPotBackend is properly defined as a base class in DeepPot.h, inheriting from DeepBaseModelBackend
  3. The inheritance hierarchy is clean and consistent:
    • DeepPotPTDeepPotBackendDeepBaseModelBackend
    • DeepPotTFDeepPotBackendDeepBaseModelBackend

The change from DeepPotBase to DeepPotBackend is part of a well-structured refactoring that establishes a clear backend-specific implementation hierarchy.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other classes that might be affected by this base class change
rg -l "class.*:.*public.*DeepPot(Base|Backend)" --type cpp --type hpp

Length of output: 99


Script:

#!/bin/bash
# Search for other classes that might be affected by this base class change
# Using .h extension instead of .hpp
rg -l "class.*:.*public.*DeepPot(Base|Backend)" --type cpp --type h

# Also search for the base class definitions
rg "class.*(DeepPotBase|DeepPotBackend)" --type cpp --type h

# Find all header files in the codebase to ensure we're not missing any extensions
fd -e h -e hpp

Length of output: 2758


Script:

#!/bin/bash
# Let's check the content of DeepPotTF.h to see if it also changed from Base to Backend
rg "DeepPotBase" source/api_cc/include/DeepPotTF.h

# Check DeepPot.h to understand the base class hierarchy
cat source/api_cc/include/DeepPot.h

Length of output: 31761

source/api_cc/include/DeepSpin.h (3)

1-10: LGTM!

The file structure follows best practices with proper license header, include guard, and necessary dependencies.


220-231: Input validation reminder

A previous review already suggested adding input validation for array dimensions. This applies to all compute methods in this class.

Also applies to: 271-285, 327-340, 384-400


540-540: Member initialization reminder

A previous review already flagged the need for proper initialization of the dps member variable.

source/api_cc/include/DeepPot.h (1)

581-582: Vector parameters properly handle multi-model outputs

The compute methods now correctly use std::vector<std::vector<VALUETYPE>> for force and virial outputs, which is essential for handling multiple model predictions in the spin calculations. The parameter ordering is consistent across all method overloads.

Also applies to: 614-617, 649-650, 688-691

source/api_c/include/c_api.h (3)

13-13: LGTM: API version bump is appropriate.

The version bump to 23 is well-documented and justified by the significant additions of spin model support.


97-109: LGTM: Well-structured base model implementation.

The new base model structures and methods provide a solid foundation for both regular and spin models. The implementation:

  • Follows consistent patterns
  • Has thorough documentation
  • Provides clear separation of concerns

Also applies to: 1132-1215


157-188: LGTM: Comprehensive spin model implementation.

The spin model implementation:

  • Maintains consistent structure with existing DeepPot implementation
  • Properly handles both double and float precision
  • Adds necessary parameters for magnetic forces

Also applies to: 368-496, 745-784

source/api_c/include/deepmd.hpp (2)

839-947: LGTM! Well-structured base class implementation

The DeepBaseModel class provides a clean abstraction with:

  • Good separation of concerns
  • Proper error handling
  • Well-documented methods
  • Type-safe parameter validation

1500-1539: ⚠️ Potential issue

Add validation for spin vector dimensions

The compute method should validate that the spin vector has the correct dimensions (nframes * natoms * 3) before computation to prevent buffer overflows.

    unsigned int natoms = atype.size();
    unsigned int nframes = natoms > 0 ? coord.size() / natoms / 3 : 1;
    assert(nframes * natoms * 3 == coord.size());
+   assert(nframes * natoms * 3 == spin.size());  // Validate spin dimensions
    if (!box.empty()) {
      assert(box.size() == nframes * 9);
    }

Likely invalid or redundant comment.

source/api_cc/include/DeepPotTF.h (3)

13-13: Update in inheritance improves code structure

The change from inheriting DeepPotBase to DeepPotBackend enhances the modularity and maintainability of the class hierarchy.


19-19: Addition of virtual destructor ensures proper cleanup

By declaring a virtual destructor, you guarantee that derived class destructors are called correctly, preventing resource leaks.


309-321: New member variables support spin system functionality

The introduction of member variables like virtual_len, spin_norm, and extended neighbor lists enhances the class's capability to handle spin models effectively.

source/lmp/pair_base.cpp (4)

373-378: Ensure allocated memory in init_style() is properly deallocated

The arrays counts, displacements, stdfsend, stdfrecv, tagsend, and tagrecv allocated in init_style() when out_each is 1 are not being deallocated in the destructor, leading to potential memory leaks.

This issue was previously raised and is still applicable. Please refer to the past review comments and ensure all allocated memory is properly freed in the destructor.


254-256: Unused local variables dx, dy, and dz

The variables dx, dy, and dz are declared but not used in make_ttm_aparam, which may lead to compiler warnings.

This issue was previously identified by static analysis tools and is still present. Consider removing these unused variables to clean up the code.


254-256: Correct variable used in dz calculation

The calculation of dz uses nynodes instead of nznodes, which appears to be a typo.

This issue was previously noted and remains unresolved. Please update the calculation:

-    double dz = domain->zprd / nynodes;
+    double dz = domain->zprd / nznodes;

415-422: Update neighbor request for LAMMPS versions

Ensure compatibility with different LAMMPS versions by correctly setting neighbor requests.

Please verify that the neighbor request setup is appropriate for the targeted LAMMPS version.

Run the following script to check for any deprecated neighbor request methods:

This will help identify any potential issues with neighbor requests across different LAMMPS versions.

✅ Verification successful

The previous command failed due to incorrect ripgrep syntax. Let's try with the correct syntax to gather information about neighbor request patterns and version-specific code across the codebase.


The neighbor request implementation is correctly version-dependent

The code correctly handles neighbor requests for different LAMMPS versions:

  • For LAMMPS >= 20220324, it uses the new add_request API with NeighConst::REQ_FULL
  • For older versions, it uses the legacy request API with appropriate flags (half = 0, full = 1)

This pattern is consistently used across the codebase, as evidenced by similar version-specific implementations in compute_deeptensor_atom.cpp. The implementation aligns with LAMMPS' evolution of the neighbor list API and maintains backward compatibility.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for usage of deprecated neighbor request methods.

# Search for neighbor request code patterns.
rg 'neighbor->request\(' --include 'pair_*.cpp' -A 3

Length of output: 496


Script:

#!/bin/bash
# Search for neighbor request code patterns with correct ripgrep syntax
rg "neighbor->request" -t cpp

# Also search for the newer style requests
rg "neighbor->add_request" -t cpp

# Search for LAMMPS version checks related to neighbor requests
rg "LAMMPS_VERSION" -t cpp -B 2 -A 4

Length of output: 13605

source/lmp/pair_deepmd.cpp (7)

87-90: Ensure Proper Initialization of Base Class

While the constructor correctly inherits from PairDeepBaseModel, it's important to ensure that all necessary initializations are performed, even if the body is empty. If any member variables or resources require explicit initialization, they should be added here to prevent potential issues.

You can verify whether additional initialization is needed by reviewing the base class constructor and checking for any required initializations that are not automatically handled.


93-94: Confirm Need for Empty Destructor

The destructor is currently empty. If the base class handles all necessary cleanup, this is acceptable. However, if there are resources or memory allocations specific to PairDeepMD, they should be properly released here.

Ensure that no additional cleanup is required for member variables introduced in PairDeepMD.


438-455: Handle Ghost Types Appropriately

The code introduces a "ghost type" when a type is not found in the model and the type name is "NULL". Ensure that this handling aligns with the intended functionality, especially since spin-related types are being removed.

Verify whether the use of a ghost type is still relevant and correctly handled in subsequent code.


556-566: Update Neighbor List Age Handling

The code adjusts ago based on conditions related to model deviation calculations. Ensure that ago is set correctly to maintain performance while ensuring accurate computations.

Confirm that setting ago = 0 when necessary does not introduce performance issues or unintended side effects.


834-840: Ensure Serial Execution Path Handles Model Deviations Appropriately

The code currently raises an error if more than one model is used in serial execution.

Confirm whether the serial version should support model deviation calculations or if it's acceptable to restrict this functionality to parallel executions.


845-850: Consider Newton's Third Law in Force Application

When applying forces in the loop over atoms, ensure that Newton's third law is correctly handled, especially if newton_pair is enabled.

Confirm that the force accumulation is symmetric across interacting atom pairs if required by the simulation's settings.


802-805: ⚠️ Potential issue

Replace std::cout with Proper Error Handling

Using std::cout for error messages is not consistent with LAMMPS error handling practices.

Apply this diff to use error->all:

      if (atom->sp_flag) {
-        std::cout << "Pair style 'deepmd' does not support spin atoms, please use "
-                     "pair style 'deepspin' instead."
-                  << std::endl;
+        error->all(FLERR, "Pair style 'deepmd' does not support spin atoms. "
+                   "Please use pair style 'deepspin' instead.");
      }

Also applies to similar code at lines 873-877 and 895-899.

Likely invalid or redundant comment.

source/api_c/src/c_api.cc (19)

48-56: LGTM!

The DP_DeepBaseModel class and its constructor, destructor, and member variables look good.


58-66: LGTM!

The DP_DeepBaseModelDevi class and its constructor, destructor, and member variables look good.


134-151: LGTM!

The DP_DeepSpin class and its constructor, destructor, and factory functions look good.


153-185: LGTM!

The DP_DeepSpinModelDevi class and its constructor, destructor, and factory functions look good.


378-408: LGTM!

The template instantiations for DP_DeepSpinCompute_variant look good.


574-609: LGTM!

The template instantiations for DP_DeepSpinComputeNList_variant look good.


997-1034: LGTM!

The template instantiations for DP_DeepSpinModelDeviComputeNList_variant look good.


1457-1475: LGTM!

The DP_DeepSpinCompute2 function looks good.


1495-1513: LGTM!

The DP_DeepSpinComputef2 function looks good.


1580-1601: Handle frame count limitation.

Similar to DP_DeepSpinComputeNList2, the DP_DeepSpinComputeNListf2 function also does not support nframes > 1. Address this limitation consistently.


1763-1781: Standardize error handling for frame count limitation.

The frame count limitation check in DP_DeepSpinModelDeviComputeNListfSP uses std::runtime_error while the rest of the codebase uses DP_REQUIRES_OK. Standardize the error handling for consistency.


1804-1825: Standardize error handling for frame count limitation.

The frame count limitation check in DP_DeepSpinModelDeviComputeNList2 uses std::runtime_error while the rest of the codebase uses DP_REQUIRES_OK. Standardize the error handling for consistency.


1848-1869: Standardize error handling for frame count limitation.

The frame count limitation check in DP_DeepSpinModelDeviComputeNListf2 uses std::runtime_error while the rest of the codebase uses DP_REQUIRES_OK. Standardize the error handling for consistency.


1930-1932: Document ownership of returned C string.

The DP_DeepBaseModelDeviCheckOK function returns a const char* pointer that is dynamically allocated. Document that the caller is responsible for freeing this memory using DP_DeleteChar to prevent memory leaks.


2000-2031: LGTM!

The DP_DeepSpin methods that delegate to DP_DeepBaseModel look good.


2033-2063: LGTM!

The DP_DeepSpinModelDevi methods that delegate to DP_DeepBaseModelDevi look good.


509-573: Verify spin vector normalization.

Similar to the DP_DeepSpinCompute_variant function, DP_DeepSpinComputeNList_variant should also validate that the input spin vectors are properly normalized before using them.

#!/bin/bash 
# Description: Verify spin vectors are normalized in `DP_DeepSpinComputeNList_variant`.

# Test: Search for the spin vector assignment.
# Expect: Normalization check before assignment.
rg -A 5 $'std::vector<VALUETYPE> spin_\(spin, spin \+ nframes \* natoms \* 3\);' 

1725-1743: 🛠️ Refactor suggestion

Standardize error handling for frame count limitation.

The frame count limitation check in DP_DeepSpinModelDeviComputeNListSP uses std::runtime_error while the rest of the codebase uses DP_REQUIRES_OK. Standardize the error handling for consistency.

Apply this diff:

-  if (nframes > 1) {
-    throw std::runtime_error("nframes > 1 not supported yet");
-  }
+  if (nframes > 1) {
+    DP_REQUIRES_OK(dp, dp->dp.set_exception("nframes > 1 not supported yet"));
+    return;
+  }

Likely invalid or redundant comment.


318-376: Verify spin vector normalization.

The DP_DeepSpinCompute_variant function should validate that the input spin vectors are properly normalized. Consider adding a check before using the spin data.

Comment on lines +57 to +58
double **scale;
unsigned numb_models;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add RAII for raw pointer members.

The class contains raw pointer members (scale, counts, displacements, tagsend, tagrecv, stdfsend, stdfrecv) but lacks proper copy control. Consider:

  1. Implementing the Rule of Three/Five
  2. Using smart pointers or containers
  3. Explicitly deleting copy operations if not needed

Also applies to: 98-101

Comment on lines +766 to +768
MPI_Reduce(&send_v[0], &recv_v[0], 9 * numb_models, MPI_DOUBLE, MPI_SUM,
0, world);
std::vector<std::vector<double>> all_virial_1(numb_models);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling for MPI communication.

The MPI_Reduce call could fail but there's no error handling. Consider checking the return value and handling potential communication failures.

-        MPI_Reduce(&send_v[0], &recv_v[0], 9 * numb_models, MPI_DOUBLE, MPI_SUM,
-                   0, world);
+        int mpi_result = MPI_Reduce(&send_v[0], &recv_v[0], 9 * numb_models, 
+                                   MPI_DOUBLE, MPI_SUM, 0, world);
+        if (mpi_result != MPI_SUCCESS) {
+          error->all(FLERR, "Failed to reduce virial values in model deviation calculation");
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
MPI_Reduce(&send_v[0], &recv_v[0], 9 * numb_models, MPI_DOUBLE, MPI_SUM,
0, world);
std::vector<std::vector<double>> all_virial_1(numb_models);
int mpi_result = MPI_Reduce(&send_v[0], &recv_v[0], 9 * numb_models,
MPI_DOUBLE, MPI_SUM, 0, world);
if (mpi_result != MPI_SUCCESS) {
error->all(FLERR, "Failed to reduce virial values in model deviation calculation");
}
std::vector<std::vector<double>> all_virial_1(numb_models);

Comment on lines +914 to +923
for (i = first; i < last; i++) {
for (int dd = 0; dd < numb_models; ++dd) {
buf[m++] = all_force[dd][3 * i + 0];
buf[m++] = all_force[dd][3 * i + 1];
buf[m++] = all_force[dd][3 * i + 2];
buf[m++] = all_force_mag[dd][3 * i + 0];
buf[m++] = all_force_mag[dd][3 * i + 1];
buf[m++] = all_force_mag[dd][3 * i + 2];
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add bounds checking for buffer access.

The buffer access in the pack_reverse_comm method lacks bounds checking, which could lead to buffer overflows.

+      if (m + 6 * numb_models > n * 6 * numb_models) {
+        error->one(FLERR, "Buffer overflow in pack_reverse_comm");
+      }
       for (int dd = 0; dd < numb_models; ++dd) {
         buf[m++] = all_force[dd][3 * i + 0];
         buf[m++] = all_force[dd][3 * i + 1];
         buf[m++] = all_force[dd][3 * i + 2];
         buf[m++] = all_force_mag[dd][3 * i + 0];
         buf[m++] = all_force_mag[dd][3 * i + 1];
         buf[m++] = all_force_mag[dd][3 * i + 2];
       }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (i = first; i < last; i++) {
for (int dd = 0; dd < numb_models; ++dd) {
buf[m++] = all_force[dd][3 * i + 0];
buf[m++] = all_force[dd][3 * i + 1];
buf[m++] = all_force[dd][3 * i + 2];
buf[m++] = all_force_mag[dd][3 * i + 0];
buf[m++] = all_force_mag[dd][3 * i + 1];
buf[m++] = all_force_mag[dd][3 * i + 2];
}
}
for (i = first; i < last; i++) {
if (m + 6 * numb_models > n * 6 * numb_models) {
error->one(FLERR, "Buffer overflow in pack_reverse_comm");
}
for (int dd = 0; dd < numb_models; ++dd) {
buf[m++] = all_force[dd][3 * i + 0];
buf[m++] = all_force[dd][3 * i + 1];
buf[m++] = all_force[dd][3 * i + 2];
buf[m++] = all_force_mag[dd][3 * i + 0];
buf[m++] = all_force_mag[dd][3 * i + 1];
buf[m++] = all_force_mag[dd][3 * i + 2];
}
}

Comment on lines +469 to +489
void ana_st(double &max,
double &min,
double &sum,
const vector<double> &vec,
const int &nloc) {
if (nloc == 0) {
return;
}
max = vec[0];
min = vec[0];
sum = vec[0];
for (unsigned ii = 1; ii < nloc; ++ii) {
if (vec[ii] > max) {
max = vec[ii];
}
if (vec[ii] < min) {
min = vec[ii];
}
sum += vec[ii];
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Prevent potential access to uninitialized elements in ana_st()

If vec is empty but nloc is greater than zero, accessing vec[0] leads to undefined behavior. Ensure that vec has at least nloc elements before accessing.

Apply this diff to add a safety check:

   if (nloc == 0) {
     return;
   }
+  if (vec.size() < static_cast<size_t>(nloc)) {
+    error->all(FLERR, "Vector size is smaller than nloc in ana_st()");
+  }
   max = vec[0];
   min = vec[0];
   sum = vec[0];

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +55 to +99
char host_name[MPI_MAX_PROCESSOR_NAME];
memset(host_name, '\0', sizeof(char) * MPI_MAX_PROCESSOR_NAME);
char(*host_names)[MPI_MAX_PROCESSOR_NAME];
int n, namelen, color, rank, nprocs, myrank;
size_t bytes;
MPI_Comm nodeComm;

MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
MPI_Get_processor_name(host_name, &namelen);

bytes = nprocs * sizeof(char[MPI_MAX_PROCESSOR_NAME]);
host_names = (char(*)[MPI_MAX_PROCESSOR_NAME])malloc(bytes);
for (int ii = 0; ii < nprocs; ii++) {
memset(host_names[ii], '\0', sizeof(char) * MPI_MAX_PROCESSOR_NAME);
}

strcpy(host_names[rank], host_name);

for (n = 0; n < nprocs; n++) {
MPI_Bcast(&(host_names[n]), MPI_MAX_PROCESSOR_NAME, MPI_CHAR, n,
MPI_COMM_WORLD);
}
qsort(host_names, nprocs, sizeof(char[MPI_MAX_PROCESSOR_NAME]), stringCmp);

color = 0;
for (n = 0; n < nprocs - 1; n++) {
if (strcmp(host_name, host_names[n]) == 0) {
break;
}
if (strcmp(host_names[n], host_names[n + 1])) {
color++;
}
}

MPI_Comm_split(MPI_COMM_WORLD, color, 0, &nodeComm);
MPI_Comm_rank(nodeComm, &myrank);

MPI_Barrier(MPI_COMM_WORLD);
int looprank = myrank;
// printf (" Assigning device %d to process on node %s rank %d,
// OK\n",looprank, host_name, rank );
free(host_names);
return looprank;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace manual memory management with std::vector in get_node_rank()

Using malloc and free can lead to potential memory leaks and is not exception-safe. It is recommended to use std::vector for automatic memory management and better code safety.

Apply this diff to refactor the code:

-  bytes = nprocs * sizeof(char[MPI_MAX_PROCESSOR_NAME]);
-  host_names = (char(*)[MPI_MAX_PROCESSOR_NAME])malloc(bytes);
-  for (int ii = 0; ii < nprocs; ii++) {
-    memset(host_names[ii], '\0', sizeof(char) * MPI_MAX_PROCESSOR_NAME);
-  }
+  std::vector<std::array<char, MPI_MAX_PROCESSOR_NAME>> host_names(nprocs);
+  for (int ii = 0; ii < nprocs; ii++) {
+    host_names[ii].fill('\0');
+  }

   strcpy(host_names[rank], host_name);

   for (n = 0; n < nprocs; n++) {
-    MPI_Bcast(&(host_names[n]), MPI_MAX_PROCESSOR_NAME, MPI_CHAR, n,
-              MPI_COMM_WORLD);
+    MPI_Bcast(host_names[n].data(), MPI_MAX_PROCESSOR_NAME, MPI_CHAR, n,
+              MPI_COMM_WORLD);
   }
   qsort(host_names, nprocs, sizeof(char[MPI_MAX_PROCESSOR_NAME]), stringCmp);

   // ...

-  free(host_names);

Note: You will also need to adjust the calls to qsort and any code that directly manipulates host_names to work with std::vector and std::array.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +499 to +508
vector<double> dspin(nall * 3, 0.);
vector<double> dfm(nall * 3, 0.);
double **sp = atom->sp;
double **fm = atom->fm;
if (atom->sp_flag) {
std::cout << "Pair style 'deepmd' does not support spin atoms, please use "
"pair style 'deepspin' instead."
<< std::endl;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove Unused Spin-Related Variables and Checks

Variables like dspin, dfm, sp, and fm are declared but not used since spin atoms are no longer supported. Additionally, the check for atom->sp_flag results in a message directing users to deepspin.

Remove the unnecessary variables and the check:

-  vector<double> dspin(nall * 3, 0.);
-  vector<double> dfm(nall * 3, 0.);
-  double **sp = atom->sp;
-  double **fm = atom->fm;
-  if (atom->sp_flag) {
-    std::cout << "Pair style 'deepmd' does not support spin atoms, please use "
-                 "pair style 'deepspin' instead."
-              << std::endl;
-  }

This streamlines the code and eliminates confusion.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
vector<double> dspin(nall * 3, 0.);
vector<double> dfm(nall * 3, 0.);
double **sp = atom->sp;
double **fm = atom->fm;
if (atom->sp_flag) {
std::cout << "Pair style 'deepmd' does not support spin atoms, please use "
"pair style 'deepspin' instead."
<< std::endl;
}

Comment on lines +302 to +318
if (!atom->sp_flag) {
fp << "#" << setw(12 - 1) << "step" << setw(18 + 1) << "max_devi_v"
<< setw(18 + 1) << "min_devi_v" << setw(18 + 1) << "avg_devi_v"
<< setw(18 + 1) << "max_devi_f" << setw(18 + 1) << "min_devi_f"
<< setw(18 + 1) << "avg_devi_f";
if (out_each) {
// at this time, we don't know how many atoms
fp << setw(18 + 1) << "atm_devi_f(N)";
}
fp << endl;
} else {
fp << "#" << setw(12 - 1) << "step" << setw(18 + 1) << "max_devi_v"
<< setw(18 + 1) << "min_devi_v" << setw(18 + 1) << "avg_devi_v"
<< setw(18 + 1) << "max_devi_fr" << setw(18 + 1) << "min_devi_fr"
<< setw(18 + 1) << "avg_devi_fr" << setw(18 + 1) << "max_devi_fm"
<< setw(18 + 1) << "min_devi_fm" << setw(18 + 1) << "avg_devi_fm"
<< endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Ensure Consistency in Output Headers

The code differentiates output headers based on whether atom->sp_flag is true or false. However, since the class no longer supports spin atoms and directs users to use deepspin, the block where atom->sp_flag is true may be unnecessary.

Consider removing the else block since atom->sp_flag should always be false in this context. This will simplify the code and prevent confusion.

             if (!atom->sp_flag) {
               fp << "#" << setw(12 - 1) << "step" << setw(18 + 1) << "max_devi_v"
                  << setw(18 + 1) << "min_devi_v" << setw(18 + 1) << "avg_devi_v"
                  << setw(18 + 1) << "max_devi_f" << setw(18 + 1) << "min_devi_f"
                  << setw(18 + 1) << "avg_devi_f";
               if (out_each) {
                 // at this time, we don't know how many atoms
                 fp << setw(18 + 1) << "atm_devi_f(N)";
               }
               fp << endl;
-            } else {
-              fp << "#" << setw(12 - 1) << "step" << setw(18 + 1) << "max_devi_v"
-                 << setw(18 + 1) << "min_devi_v" << setw(18 + 1) << "avg_devi_v"
-                 << setw(18 + 1) << "max_devi_fr" << setw(18 + 1) << "min_devi_fr"
-                 << setw(18 + 1) << "avg_devi_fr" << setw(18 + 1) << "max_devi_fm"
-                 << setw(18 + 1) << "min_devi_fm" << setw(18 + 1) << "avg_devi_fm"
-                 << endl;
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!atom->sp_flag) {
fp << "#" << setw(12 - 1) << "step" << setw(18 + 1) << "max_devi_v"
<< setw(18 + 1) << "min_devi_v" << setw(18 + 1) << "avg_devi_v"
<< setw(18 + 1) << "max_devi_f" << setw(18 + 1) << "min_devi_f"
<< setw(18 + 1) << "avg_devi_f";
if (out_each) {
// at this time, we don't know how many atoms
fp << setw(18 + 1) << "atm_devi_f(N)";
}
fp << endl;
} else {
fp << "#" << setw(12 - 1) << "step" << setw(18 + 1) << "max_devi_v"
<< setw(18 + 1) << "min_devi_v" << setw(18 + 1) << "avg_devi_v"
<< setw(18 + 1) << "max_devi_fr" << setw(18 + 1) << "min_devi_fr"
<< setw(18 + 1) << "avg_devi_fr" << setw(18 + 1) << "max_devi_fm"
<< setw(18 + 1) << "min_devi_fm" << setw(18 + 1) << "avg_devi_fm"
<< endl;
if (!atom->sp_flag) {
fp << "#" << setw(12 - 1) << "step" << setw(18 + 1) << "max_devi_v"
<< setw(18 + 1) << "min_devi_v" << setw(18 + 1) << "avg_devi_v"
<< setw(18 + 1) << "max_devi_f" << setw(18 + 1) << "min_devi_f"
<< setw(18 + 1) << "avg_devi_f";
if (out_each) {
// at this time, we don't know how many atoms
fp << setw(18 + 1) << "atm_devi_f(N)";
}
fp << endl;
}

Comment on lines +708 to +828
double all_f_min = 0, all_f_max = 0, all_f_avg = 0;
double all_fm_min = 0, all_fm_max = 0, all_fm_avg = 0;
MPI_Reduce(&min, &all_f_min, 1, MPI_DOUBLE, MPI_MIN, 0, world);
MPI_Reduce(&max, &all_f_max, 1, MPI_DOUBLE, MPI_MAX, 0, world);
MPI_Reduce(&avg, &all_f_avg, 1, MPI_DOUBLE, MPI_SUM, 0, world);
all_f_avg /= double(atom->natoms);
// std v
std::vector<double> send_v(9 * numb_models);
std::vector<double> recv_v(9 * numb_models);
for (int kk = 0; kk < numb_models; ++kk) {
for (int ii = 0; ii < 9; ++ii) {
send_v[kk * 9 + ii] = all_virial[kk][ii] / double(atom->natoms);
}
}
MPI_Reduce(&send_v[0], &recv_v[0], 9 * numb_models, MPI_DOUBLE, MPI_SUM,
0, world);
std::vector<std::vector<double>> all_virial_1(numb_models);
std::vector<double> avg_virial, std_virial;
for (int kk = 0; kk < numb_models; ++kk) {
all_virial_1[kk].resize(9);
for (int ii = 0; ii < 9; ++ii) {
all_virial_1[kk][ii] = recv_v[kk * 9 + ii];
}
}
double all_v_min = numeric_limits<double>::max(), all_v_max = 0,
all_v_avg = 0;
if (rank == 0) {
deep_pot_model_devi.compute_avg(avg_virial, all_virial_1);
deep_pot_model_devi.compute_std(std_virial, avg_virial, all_virial_1,
1);
if (out_rel_v == 1) {
deep_pot_model_devi.compute_relative_std(std_virial, avg_virial,
eps_v, 1);
}
for (int ii = 0; ii < 9; ++ii) {
if (std_virial[ii] > all_v_max) {
all_v_max = std_virial[ii];
}
if (std_virial[ii] < all_v_min) {
all_v_min = std_virial[ii];
}
all_v_avg += std_virial[ii] * std_virial[ii];
}
all_v_avg = sqrt(all_v_avg / 9);
}
if (rank == 0) {
all_v_max *= ener_unit_cvt_factor;
all_v_min *= ener_unit_cvt_factor;
all_v_avg *= ener_unit_cvt_factor;
all_f_max *= force_unit_cvt_factor;
all_f_min *= force_unit_cvt_factor;
all_f_avg *= force_unit_cvt_factor;
fp << setw(12) << update->ntimestep << " " << setw(18) << all_v_max
<< " " << setw(18) << all_v_min << " " << setw(18) << all_v_avg
<< " " << setw(18) << all_f_max << " " << setw(18) << all_f_min
<< " " << setw(18) << all_f_avg;
}
if (out_each == 1) {
// need support for spin atomic force.
vector<double> std_f_all(atom->natoms);
// Gather std_f and tags
tagint *tag = atom->tag;
int nprocs = comm->nprocs;
// Grow arrays if necessary
if (atom->natoms > stdf_comm_buff_size) {
stdf_comm_buff_size = atom->natoms;
memory->destroy(stdfsend);
memory->destroy(stdfrecv);
memory->destroy(tagsend);
memory->destroy(tagrecv);
memory->create(stdfsend, stdf_comm_buff_size, "deepmd:stdfsendall");
memory->create(stdfrecv, stdf_comm_buff_size, "deepmd:stdfrecvall");
memory->create(tagsend, stdf_comm_buff_size, "deepmd:tagsendall");
memory->create(tagrecv, stdf_comm_buff_size, "deepmd:tagrecvall");
}
for (int ii = 0; ii < nlocal; ii++) {
tagsend[ii] = tag[ii];
stdfsend[ii] = std_f[ii];
}
MPI_Gather(&nlocal, 1, MPI_INT, counts, 1, MPI_INT, 0, world);
displacements[0] = 0;
for (int ii = 0; ii < nprocs - 1; ii++) {
displacements[ii + 1] = displacements[ii] + counts[ii];
}
MPI_Gatherv(tagsend, nlocal, MPI_LMP_TAGINT, tagrecv, counts,
displacements, MPI_LMP_TAGINT, 0, world);
MPI_Gatherv(stdfsend, nlocal, MPI_DOUBLE, stdfrecv, counts,
displacements, MPI_DOUBLE, 0, world);
if (rank == 0) {
for (int dd = 0; dd < atom->natoms; ++dd) {
std_f_all[tagrecv[dd] - 1] = stdfrecv[dd] * force_unit_cvt_factor;
}
for (int dd = 0; dd < atom->natoms; ++dd) {
fp << " " << setw(18) << std_f_all[dd];
}
}
}
if (rank == 0) {
fp << endl;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize Model Deviation Logging

In the block handling model deviation output, ensure that:

  • Variables are properly initialized and used.
  • Unused variables like std_fm, tmp_avg_fm, all_fm_min, all_fm_max, all_fm_avg are removed.
  • Logging only includes relevant information since spin atoms are not supported.

Apply changes to remove unused variables and adjust the logging accordingly.

          vector<double> std_f;
          vector<double> tmp_avg_f;
-         vector<double> std_fm;
-         vector<double> tmp_avg_fm;
          deep_pot_model_devi.compute_avg(tmp_avg_f, all_force);
          deep_pot_model_devi.compute_std_f(std_f, tmp_avg_f, all_force);
          if (out_rel == 1) {
            deep_pot_model_devi.compute_relative_std_f(std_f, tmp_avg_f, eps);
          }
          double min = numeric_limits<double>::max(), max = 0, avg = 0;
          ana_st(max, min, avg, std_f, nlocal);
          double all_f_min = 0, all_f_max = 0, all_f_avg = 0;
-         double all_fm_min = 0, all_fm_max = 0, all_fm_avg = 0;
          MPI_Reduce(&min, &all_f_min, 1, MPI_DOUBLE, MPI_MIN, 0, world);
          MPI_Reduce(&max, &all_f_max, 1, MPI_DOUBLE, MPI_MAX, 0, world);
          MPI_Reduce(&avg, &all_f_avg, 1, MPI_DOUBLE, MPI_SUM, 0, world);
          all_f_avg /= double(atom->natoms);
          // std v

Adjust the code to ensure only relevant data is calculated and outputted.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (out_freq > 0 && update->ntimestep % out_freq == 0) {
int rank = comm->me;
// std force
if (newton_pair) {
#if LAMMPS_VERSION_NUMBER >= 20220324
comm->reverse_comm(this);
#else
comm->reverse_comm_pair(this);
#endif
}
vector<double> std_f;
vector<double> tmp_avg_f;
vector<double> std_fm;
vector<double> tmp_avg_fm;
deep_pot_model_devi.compute_avg(tmp_avg_f, all_force);
deep_pot_model_devi.compute_std_f(std_f, tmp_avg_f, all_force);
if (out_rel == 1) {
deep_pot_model_devi.compute_relative_std_f(std_f, tmp_avg_f, eps);
}
double min = numeric_limits<double>::max(), max = 0, avg = 0;
ana_st(max, min, avg, std_f, nlocal);
double all_f_min = 0, all_f_max = 0, all_f_avg = 0;
double all_fm_min = 0, all_fm_max = 0, all_fm_avg = 0;
MPI_Reduce(&min, &all_f_min, 1, MPI_DOUBLE, MPI_MIN, 0, world);
MPI_Reduce(&max, &all_f_max, 1, MPI_DOUBLE, MPI_MAX, 0, world);
MPI_Reduce(&avg, &all_f_avg, 1, MPI_DOUBLE, MPI_SUM, 0, world);
all_f_avg /= double(atom->natoms);
// std v
std::vector<double> send_v(9 * numb_models);
std::vector<double> recv_v(9 * numb_models);
for (int kk = 0; kk < numb_models; ++kk) {
for (int ii = 0; ii < 9; ++ii) {
send_v[kk * 9 + ii] = all_virial[kk][ii] / double(atom->natoms);
}
}
MPI_Reduce(&send_v[0], &recv_v[0], 9 * numb_models, MPI_DOUBLE, MPI_SUM,
0, world);
std::vector<std::vector<double>> all_virial_1(numb_models);
std::vector<double> avg_virial, std_virial;
for (int kk = 0; kk < numb_models; ++kk) {
all_virial_1[kk].resize(9);
for (int ii = 0; ii < 9; ++ii) {
all_virial_1[kk][ii] = recv_v[kk * 9 + ii];
}
}
double all_v_min = numeric_limits<double>::max(), all_v_max = 0,
all_v_avg = 0;
if (rank == 0) {
deep_pot_model_devi.compute_avg(avg_virial, all_virial_1);
deep_pot_model_devi.compute_std(std_virial, avg_virial, all_virial_1,
1);
if (out_rel_v == 1) {
deep_pot_model_devi.compute_relative_std(std_virial, avg_virial,
eps_v, 1);
}
for (int ii = 0; ii < 9; ++ii) {
if (std_virial[ii] > all_v_max) {
all_v_max = std_virial[ii];
}
if (std_virial[ii] < all_v_min) {
all_v_min = std_virial[ii];
}
all_v_avg += std_virial[ii] * std_virial[ii];
}
all_v_avg = sqrt(all_v_avg / 9);
}
if (rank == 0) {
all_v_max *= ener_unit_cvt_factor;
all_v_min *= ener_unit_cvt_factor;
all_v_avg *= ener_unit_cvt_factor;
all_f_max *= force_unit_cvt_factor;
all_f_min *= force_unit_cvt_factor;
all_f_avg *= force_unit_cvt_factor;
fp << setw(12) << update->ntimestep << " " << setw(18) << all_v_max
<< " " << setw(18) << all_v_min << " " << setw(18) << all_v_avg
<< " " << setw(18) << all_f_max << " " << setw(18) << all_f_min
<< " " << setw(18) << all_f_avg;
}
if (out_each == 1) {
// need support for spin atomic force.
vector<double> std_f_all(atom->natoms);
// Gather std_f and tags
tagint *tag = atom->tag;
int nprocs = comm->nprocs;
// Grow arrays if necessary
if (atom->natoms > stdf_comm_buff_size) {
stdf_comm_buff_size = atom->natoms;
memory->destroy(stdfsend);
memory->destroy(stdfrecv);
memory->destroy(tagsend);
memory->destroy(tagrecv);
memory->create(stdfsend, stdf_comm_buff_size, "deepmd:stdfsendall");
memory->create(stdfrecv, stdf_comm_buff_size, "deepmd:stdfrecvall");
memory->create(tagsend, stdf_comm_buff_size, "deepmd:tagsendall");
memory->create(tagrecv, stdf_comm_buff_size, "deepmd:tagrecvall");
}
for (int ii = 0; ii < nlocal; ii++) {
tagsend[ii] = tag[ii];
stdfsend[ii] = std_f[ii];
}
MPI_Gather(&nlocal, 1, MPI_INT, counts, 1, MPI_INT, 0, world);
displacements[0] = 0;
for (int ii = 0; ii < nprocs - 1; ii++) {
displacements[ii + 1] = displacements[ii] + counts[ii];
}
MPI_Gatherv(tagsend, nlocal, MPI_LMP_TAGINT, tagrecv, counts,
displacements, MPI_LMP_TAGINT, 0, world);
MPI_Gatherv(stdfsend, nlocal, MPI_DOUBLE, stdfrecv, counts,
displacements, MPI_DOUBLE, 0, world);
if (rank == 0) {
for (int dd = 0; dd < atom->natoms; ++dd) {
std_f_all[tagrecv[dd] - 1] = stdfrecv[dd] * force_unit_cvt_factor;
}
for (int dd = 0; dd < atom->natoms; ++dd) {
fp << " " << setw(18) << std_f_all[dd];
}
}
}
if (rank == 0) {
fp << endl;
}
if (out_freq > 0 && update->ntimestep % out_freq == 0) {
int rank = comm->me;
// std force
if (newton_pair) {
#if LAMMPS_VERSION_NUMBER >= 20220324
comm->reverse_comm(this);
#else
comm->reverse_comm_pair(this);
#endif
}
vector<double> std_f;
vector<double> tmp_avg_f;
deep_pot_model_devi.compute_avg(tmp_avg_f, all_force);
deep_pot_model_devi.compute_std_f(std_f, tmp_avg_f, all_force);
if (out_rel == 1) {
deep_pot_model_devi.compute_relative_std_f(std_f, tmp_avg_f, eps);
}
double min = numeric_limits<double>::max(), max = 0, avg = 0;
ana_st(max, min, avg, std_f, nlocal);
double all_f_min = 0, all_f_max = 0, all_f_avg = 0;
MPI_Reduce(&min, &all_f_min, 1, MPI_DOUBLE, MPI_MIN, 0, world);
MPI_Reduce(&max, &all_f_max, 1, MPI_DOUBLE, MPI_MAX, 0, world);
MPI_Reduce(&avg, &all_f_avg, 1, MPI_DOUBLE, MPI_SUM, 0, world);
all_f_avg /= double(atom->natoms);
// std v
std::vector<double> send_v(9 * numb_models);
std::vector<double> recv_v(9 * numb_models);
for (int kk = 0; kk < numb_models; ++kk) {
for (int ii = 0; ii < 9; ++ii) {
send_v[kk * 9 + ii] = all_virial[kk][ii] / double(atom->natoms);
}
}
MPI_Reduce(&send_v[0], &recv_v[0], 9 * numb_models, MPI_DOUBLE, MPI_SUM,
0, world);
std::vector<std::vector<double>> all_virial_1(numb_models);
std::vector<double> avg_virial, std_virial;
for (int kk = 0; kk < numb_models; ++kk) {
all_virial_1[kk].resize(9);
for (int ii = 0; ii < 9; ++ii) {
all_virial_1[kk][ii] = recv_v[kk * 9 + ii];
}
}
double all_v_min = numeric_limits<double>::max(), all_v_max = 0,
all_v_avg = 0;
if (rank == 0) {
deep_pot_model_devi.compute_avg(avg_virial, all_virial_1);
deep_pot_model_devi.compute_std(std_virial, avg_virial, all_virial_1,
1);
if (out_rel_v == 1) {
deep_pot_model_devi.compute_relative_std(std_virial, avg_virial,
eps_v, 1);
}
for (int ii = 0; ii < 9; ++ii) {
if (std_virial[ii] > all_v_max) {
all_v_max = std_virial[ii];
}
if (std_virial[ii] < all_v_min) {
all_v_min = std_virial[ii];
}
all_v_avg += std_virial[ii] * std_virial[ii];
}
all_v_avg = sqrt(all_v_avg / 9);
}
if (rank == 0) {
all_v_max *= ener_unit_cvt_factor;
all_v_min *= ener_unit_cvt_factor;
all_v_avg *= ener_unit_cvt_factor;
all_f_max *= force_unit_cvt_factor;
all_f_min *= force_unit_cvt_factor;
all_f_avg *= force_unit_cvt_factor;
fp << setw(12) << update->ntimestep << " " << setw(18) << all_v_max
<< " " << setw(18) << all_v_min << " " << setw(18) << all_v_avg
<< " " << setw(18) << all_f_max << " " << setw(18) << all_f_min
<< " " << setw(18) << all_f_avg;
}
if (out_each == 1) {
// need support for spin atomic force.
vector<double> std_f_all(atom->natoms);
// Gather std_f and tags
tagint *tag = atom->tag;
int nprocs = comm->nprocs;
// Grow arrays if necessary
if (atom->natoms > stdf_comm_buff_size) {
stdf_comm_buff_size = atom->natoms;
memory->destroy(stdfsend);
memory->destroy(stdfrecv);
memory->destroy(tagsend);
memory->destroy(tagrecv);
memory->create(stdfsend, stdf_comm_buff_size, "deepmd:stdfsendall");
memory->create(stdfrecv, stdf_comm_buff_size, "deepmd:stdfrecvall");
memory->create(tagsend, stdf_comm_buff_size, "deepmd:tagsendall");
memory->create(tagrecv, stdf_comm_buff_size, "deepmd:tagrecvall");
}
for (int ii = 0; ii < nlocal; ii++) {
tagsend[ii] = tag[ii];
stdfsend[ii] = std_f[ii];
}
MPI_Gather(&nlocal, 1, MPI_INT, counts, 1, MPI_INT, 0, world);
displacements[0] = 0;
for (int ii = 0; ii < nprocs - 1; ii++) {
displacements[ii + 1] = displacements[ii] + counts[ii];
}
MPI_Gatherv(tagsend, nlocal, MPI_LMP_TAGINT, tagrecv, counts,
displacements, MPI_LMP_TAGINT, 0, world);
MPI_Gatherv(stdfsend, nlocal, MPI_DOUBLE, stdfrecv, counts,
displacements, MPI_DOUBLE, 0, world);
if (rank == 0) {
for (int dd = 0; dd < atom->natoms; ++dd) {
std_f_all[tagrecv[dd] - 1] = stdfrecv[dd] * force_unit_cvt_factor;
}
for (int dd = 0; dd < atom->natoms; ++dd) {
fp << " " << setw(18) << std_f_all[dd];
}
}
}
if (rank == 0) {
fp << endl;
}

Comment on lines +1536 to +1557
void DP_DeepSpinComputeNList2(DP_DeepSpin* dp,
const int nframes,
const int natoms,
const double* coord,
const double* spin,
const int* atype,
const double* cell,
const int nghost,
const DP_Nlist* nlist,
const int ago,
const double* fparam,
const double* aparam,
double* energy,
double* force,
double* force_mag,
double* virial,
double* atomic_energy,
double* atomic_virial) {
DP_DeepSpinComputeNList_variant<double>(
dp, nframes, natoms, coord, spin, atype, cell, nghost, nlist, ago, fparam,
aparam, energy, force, force_mag, virial, atomic_energy, atomic_virial);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle frame count limitation.

The DP_DeepSpinComputeNList2 function does not support nframes > 1. Consider implementing support for multiple frames or clearly document this limitation.

Do you want me to open a GitHub issue to track implementing multi-frame support or updating the documentation?

Comment on lines +913 to +996
// support spin multi model.
template <typename VALUETYPE>
void DP_DeepSpinModelDeviComputeNList_variant(DP_DeepSpinModelDevi* dp,
const int nframes,
const int natoms,
const VALUETYPE* coord,
const VALUETYPE* spin,
const int* atype,
const VALUETYPE* cell,
const int nghost,
const DP_Nlist* nlist,
const int ago,
const VALUETYPE* fparam,
const VALUETYPE* aparam,
double* energy,
VALUETYPE* force,
VALUETYPE* force_mag,
VALUETYPE* virial,
VALUETYPE* atomic_energy,
VALUETYPE* atomic_virial) {
if (nframes > 1) {
throw std::runtime_error("nframes > 1 not supported yet");
}
// init C++ vectors from C arrays
std::vector<VALUETYPE> coord_(coord, coord + natoms * 3);
std::vector<VALUETYPE> spin_(spin, spin + natoms * 3);
std::vector<int> atype_(atype, atype + natoms);
std::vector<VALUETYPE> cell_;
if (cell) {
// pbc
cell_.assign(cell, cell + 9);
}
std::vector<VALUETYPE> fparam_;
if (fparam) {
fparam_.assign(fparam, fparam + dp->dfparam);
}
std::vector<VALUETYPE> aparam_;
if (aparam) {
aparam_.assign(
aparam,
aparam + (dp->aparam_nall ? natoms : (natoms - nghost)) * dp->daparam);
}
// different from DeepPot
std::vector<double> e;
std::vector<std::vector<VALUETYPE>> f, fm, v, ae, av;
if (atomic_energy || atomic_virial) {
DP_REQUIRES_OK(
dp, dp->dp.compute(e, f, fm, v, ae, av, coord_, spin_, atype_, cell_,
nghost, nlist->nl, ago, fparam_, aparam_));
} else {
DP_REQUIRES_OK(
dp, dp->dp.compute(e, f, fm, v, coord_, spin_, atype_, cell_, nghost,
nlist->nl, ago, fparam_, aparam_));
}
// 2D vector to 2D array, flatten first
if (energy) {
std::copy(e.begin(), e.end(), energy);
}
if (force) {
std::vector<VALUETYPE> f_flat;
flatten_vector(f_flat, f);
std::copy(f_flat.begin(), f_flat.end(), force);
}
if (force_mag) {
std::vector<VALUETYPE> f_mag_flat;
flatten_vector(f_mag_flat, fm);
std::copy(f_mag_flat.begin(), f_mag_flat.end(), force_mag);
}
if (virial) {
std::vector<VALUETYPE> v_flat;
flatten_vector(v_flat, v);
std::copy(v_flat.begin(), v_flat.end(), virial);
}
if (atomic_energy) {
std::vector<VALUETYPE> ae_flat;
flatten_vector(ae_flat, ae);
std::copy(ae_flat.begin(), ae_flat.end(), atomic_energy);
}
if (atomic_virial) {
std::vector<VALUETYPE> av_flat;
flatten_vector(av_flat, av);
std::copy(av_flat.begin(), av_flat.end(), atomic_virial);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Standardize error handling for frame count limitation.

The frame count limitation check uses std::runtime_error while the rest of the codebase uses DP_REQUIRES_OK. Standardize the error handling for consistency.

Apply this diff:

-  if (nframes > 1) {
-    throw std::runtime_error("nframes > 1 not supported yet");
-  }
+  if (nframes > 1) {
+    DP_REQUIRES_OK(dp, dp->dp.set_exception("nframes > 1 not supported yet"));
+    return;
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// support spin multi model.
template <typename VALUETYPE>
void DP_DeepSpinModelDeviComputeNList_variant(DP_DeepSpinModelDevi* dp,
const int nframes,
const int natoms,
const VALUETYPE* coord,
const VALUETYPE* spin,
const int* atype,
const VALUETYPE* cell,
const int nghost,
const DP_Nlist* nlist,
const int ago,
const VALUETYPE* fparam,
const VALUETYPE* aparam,
double* energy,
VALUETYPE* force,
VALUETYPE* force_mag,
VALUETYPE* virial,
VALUETYPE* atomic_energy,
VALUETYPE* atomic_virial) {
if (nframes > 1) {
throw std::runtime_error("nframes > 1 not supported yet");
}
// init C++ vectors from C arrays
std::vector<VALUETYPE> coord_(coord, coord + natoms * 3);
std::vector<VALUETYPE> spin_(spin, spin + natoms * 3);
std::vector<int> atype_(atype, atype + natoms);
std::vector<VALUETYPE> cell_;
if (cell) {
// pbc
cell_.assign(cell, cell + 9);
}
std::vector<VALUETYPE> fparam_;
if (fparam) {
fparam_.assign(fparam, fparam + dp->dfparam);
}
std::vector<VALUETYPE> aparam_;
if (aparam) {
aparam_.assign(
aparam,
aparam + (dp->aparam_nall ? natoms : (natoms - nghost)) * dp->daparam);
}
// different from DeepPot
std::vector<double> e;
std::vector<std::vector<VALUETYPE>> f, fm, v, ae, av;
if (atomic_energy || atomic_virial) {
DP_REQUIRES_OK(
dp, dp->dp.compute(e, f, fm, v, ae, av, coord_, spin_, atype_, cell_,
nghost, nlist->nl, ago, fparam_, aparam_));
} else {
DP_REQUIRES_OK(
dp, dp->dp.compute(e, f, fm, v, coord_, spin_, atype_, cell_, nghost,
nlist->nl, ago, fparam_, aparam_));
}
// 2D vector to 2D array, flatten first
if (energy) {
std::copy(e.begin(), e.end(), energy);
}
if (force) {
std::vector<VALUETYPE> f_flat;
flatten_vector(f_flat, f);
std::copy(f_flat.begin(), f_flat.end(), force);
}
if (force_mag) {
std::vector<VALUETYPE> f_mag_flat;
flatten_vector(f_mag_flat, fm);
std::copy(f_mag_flat.begin(), f_mag_flat.end(), force_mag);
}
if (virial) {
std::vector<VALUETYPE> v_flat;
flatten_vector(v_flat, v);
std::copy(v_flat.begin(), v_flat.end(), virial);
}
if (atomic_energy) {
std::vector<VALUETYPE> ae_flat;
flatten_vector(ae_flat, ae);
std::copy(ae_flat.begin(), ae_flat.end(), atomic_energy);
}
if (atomic_virial) {
std::vector<VALUETYPE> av_flat;
flatten_vector(av_flat, av);
std::copy(av_flat.begin(), av_flat.end(), atomic_virial);
}
}
// support spin multi model.
template <typename VALUETYPE>
void DP_DeepSpinModelDeviComputeNList_variant(DP_DeepSpinModelDevi* dp,
const int nframes,
const int natoms,
const VALUETYPE* coord,
const VALUETYPE* spin,
const int* atype,
const VALUETYPE* cell,
const int nghost,
const DP_Nlist* nlist,
const int ago,
const VALUETYPE* fparam,
const VALUETYPE* aparam,
double* energy,
VALUETYPE* force,
VALUETYPE* force_mag,
VALUETYPE* virial,
VALUETYPE* atomic_energy,
VALUETYPE* atomic_virial) {
if (nframes > 1) {
DP_REQUIRES_OK(dp, dp->dp.set_exception("nframes > 1 not supported yet"));
return;
}
// init C++ vectors from C arrays
std::vector<VALUETYPE> coord_(coord, coord + natoms * 3);
std::vector<VALUETYPE> spin_(spin, spin + natoms * 3);
std::vector<int> atype_(atype, atype + natoms);
std::vector<VALUETYPE> cell_;
if (cell) {
// pbc
cell_.assign(cell, cell + 9);
}
std::vector<VALUETYPE> fparam_;
if (fparam) {
fparam_.assign(fparam, fparam + dp->dfparam);
}
std::vector<VALUETYPE> aparam_;
if (aparam) {
aparam_.assign(
aparam,
aparam + (dp->aparam_nall ? natoms : (natoms - nghost)) * dp->daparam);
}
// different from DeepPot
std::vector<double> e;
std::vector<std::vector<VALUETYPE>> f, fm, v, ae, av;
if (atomic_energy || atomic_virial) {
DP_REQUIRES_OK(
dp, dp->dp.compute(e, f, fm, v, ae, av, coord_, spin_, atype_, cell_,
nghost, nlist->nl, ago, fparam_, aparam_));
} else {
DP_REQUIRES_OK(
dp, dp->dp.compute(e, f, fm, v, coord_, spin_, atype_, cell_, nghost,
nlist->nl, ago, fparam_, aparam_));
}
// 2D vector to 2D array, flatten first
if (energy) {
std::copy(e.begin(), e.end(), energy);
}
if (force) {
std::vector<VALUETYPE> f_flat;
flatten_vector(f_flat, f);
std::copy(f_flat.begin(), f_flat.end(), force);
}
if (force_mag) {
std::vector<VALUETYPE> f_mag_flat;
flatten_vector(f_mag_flat, fm);
std::copy(f_mag_flat.begin(), f_mag_flat.end(), force_mag);
}
if (virial) {
std::vector<VALUETYPE> v_flat;
flatten_vector(v_flat, v);
std::copy(v_flat.begin(), v_flat.end(), virial);
}
if (atomic_energy) {
std::vector<VALUETYPE> ae_flat;
flatten_vector(ae_flat, ae);
std::copy(ae_flat.begin(), ae_flat.end(), atomic_energy);
}
if (atomic_virial) {
std::vector<VALUETYPE> av_flat;
flatten_vector(av_flat, av);
std::copy(av_flat.begin(), av_flat.end(), atomic_virial);
}
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
source/lmp/tests/test_lammps_spin.py (2)

102-108: Add error handling for file operations

The setup and teardown functions should handle potential file operation errors gracefully.

 def setup_module():
+    try:
         write_lmp_data_spin(box, coord, spin, type_NiO, data_file)
+    except Exception as e:
+        pytest.skip(f"Failed to create test data file: {e}")

 def teardown_module():
+    try:
         os.remove(data_file)
+    except FileNotFoundError:
+        pass  # File already removed
+    except Exception as e:
+        print(f"Warning: Failed to cleanup test data file: {e}")

214-230: Parameterize MPI process count

The number of MPI processes is hardcoded to 2. Consider parameterizing this value to test with different numbers of processes.

 @pytest.mark.parametrize(
-    ("balance_args",),
-    [(["--balance"],), ([],)],
+    ("balance_args", "n_procs"),
+    [
+        (["--balance"], 2),
+        (["--balance"], 4),
+        ([], 2),
+        ([], 4),
+    ],
 )
-def test_pair_deepmd_mpi(balance_args: list):
+def test_pair_deepmd_mpi(balance_args: list, n_procs: int):
     with tempfile.NamedTemporaryFile() as f:
         sp.check_call(
             [
                 "mpirun",
                 "-n",
-                "2",
+                str(n_procs),
                 sys.executable,
                 Path(__file__).parent / "run_mpi_pair_deepmd_spin.py",
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between af09efd and a532c33.

📒 Files selected for processing (2)
  • source/lmp/tests/test_lammps_spin.py (1 hunks)
  • source/lmp/tests/test_lammps_spin_pt.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • source/lmp/tests/test_lammps_spin_pt.py

@iProzd
Copy link
Collaborator Author

iProzd commented Nov 7, 2024

The conversations are not readable. I'll open up another clean PR for review.

Copy link

codecov bot commented Nov 7, 2024

Codecov Report

Attention: Patch coverage is 67.64507% with 959 lines in your changes missing coverage. Please review.

Project coverage is 83.68%. Comparing base (9699349) to head (ab15e47).
Report is 131 commits behind head on devel.

Files with missing lines Patch % Lines
source/lmp/pair_deepspin.cpp 52.06% 215 Missing and 52 partials ⚠️
source/api_c/src/c_api.cc 42.04% 122 Missing and 20 partials ⚠️
source/api_c/include/deepmd.hpp 61.76% 106 Missing and 24 partials ⚠️
source/lmp/pair_base.cpp 59.35% 106 Missing and 7 partials ⚠️
source/api_cc/src/DeepSpinTF.cc 74.25% 71 Missing and 41 partials ⚠️
source/lmp/pair_deepmd.cpp 76.35% 52 Missing and 22 partials ⚠️
source/api_cc/src/DeepSpinPT.cc 78.21% 47 Missing and 14 partials ⚠️
source/api_cc/src/DeepSpin.cc 56.56% 36 Missing and 7 partials ⚠️
source/api_cc/src/DeepBaseModel.cc 82.53% 9 Missing and 2 partials ⚠️
source/api_cc/src/DeepPotTF.cc 0.00% 4 Missing ⚠️
... and 1 more
Additional details and impacted files
@@            Coverage Diff             @@
##            devel    #4216      +/-   ##
==========================================
- Coverage   84.42%   83.68%   -0.75%     
==========================================
  Files         570      584      +14     
  Lines       53107    55119    +2012     
  Branches     3059     3328     +269     
==========================================
+ Hits        44836    46124    +1288     
- Misses       7307     7896     +589     
- Partials      964     1099     +135     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

github-merge-queue bot pushed a commit that referenced this pull request Nov 11, 2024
The conversations in #4216 are not readable. I opened this clean one for
reviewers.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Release Notes

- **New Features**
- Introduced support for spin configurations within the DeepMD
framework.
- Added `PairDeepSpin` class for integrating spin models into LAMMPS
simulations.
- Enhanced `DeepSpin` and `DeepSpinModelDevi` classes with new methods
for energy and force calculations.
  - Updated `DeepPotTF` class to compute atomic energies and virials.
- Added a new function for writing LMP data that includes spin
information.

- **Bug Fixes**
- Improved error handling for unsupported configurations in spin
calculations.

- **Tests**
- Added comprehensive unit tests for `DeepSpin` and `DeepSpinModelDevi`
classes to validate functionality and ensure accuracy in computations.
- Introduced tests for verifying spin interactions without periodic
boundary conditions.
  - Developed tests for MPI-enabled versions of spin interactions.

- **Documentation**
- Updated scripts and tests to reflect new functionalities and ensure
clarity in usage.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Duo <[email protected]>
Signed-off-by: Jinzhe Zeng <[email protected]>
Co-authored-by: hztttt <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Lysithea <[email protected]>
Co-authored-by: hztttt <[email protected]>
Co-authored-by: Jinzhe Zeng <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature Request] Support C++ interface for pytorch spin model.
4 participants