diff --git a/.gitignore b/.gitignore index e95b54f..ecc80b6 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,22 @@ build/ .DS_Store Thumbs.db +# Opencode +.opencode + # Temporary / generated files *.log temp_*.xyz + +# additional hygiene patterns +*.tmp +*.bak +*~ +*.egg +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +.coverage +htmlcov/ +.omo/ +.claude/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..a04d147 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,38 @@ +# GPUMDkit + +GPUMDkit is a Bash + Python command-line toolkit for [GPUMD](https://gpumd.org/) and [NEP](https://gitlab.com/brucefan1983/nep) — molecular dynamics and neuroevolution potential programs. It provides format conversion, structure sampling, workflows, property calculation, plotting, and analysis utilities. + +**Entry point**: `gpumdkit.sh` — dual-mode (interactive menu + CLI flags): + +```bash +gpumdkit.sh # Interactive mode +gpumdkit.sh -h # Show all CLI flags +gpumdkit.sh -plt train # Plot NEP training +gpumdkit.sh -calc msd dump.xyz Li 10 # Calculate MSD +gpumdkit.sh -dp2xyz database train.xyz # DeepMD npy → extxyz +``` + +**Documentation**: https://zhyan0603.github.io/GPUMDkit/ + +## Agent Skills + +When the user asks about GPUMDkit features, use the skills in `.opencode/skills/`: + +| Skill | Use When | +|-------|----------| +| `gpumdkit-main` | General usage, navigation, entry point | +| `gpumdkit-format-conversion` | Converting structure files between formats | +| `gpumdkit-calculators` | Computing material properties | +| `gpumdkit-analyzers` | Analyzing structures and datasets | +| `gpumdkit-visualization` | Plotting simulation data | +| `gpumdkit-workflows` | Batch processing and automation | +| `gpumdkit-sampling` | Sampling and selecting structures | + +## If You Need to Modify Code + +**Read [skills/gpumdkit-contributing/SKILL.md](skills/gpumdkit-contributing/SKILL.md) first.** It contains all coding conventions, function templates, shell/Python patterns, and explicit rejections (things NOT to propose). The project follows a strict minimum-invasion principle — do not touch working code unless fixing a confirmed bug. + +Key facts: +- Tutorials are bilingual (`docs/tutorials/en/` + `zh/`). Feature changes must update both languages. +- After Python edits: `python3 -m py_compile ` then clean `__pycache__`. +- After doc edits: `mkdocs build -f docs/mkdocs.yml`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 31f045c..21122c6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,10 @@ # Contributing to GPUMDkit +

+ English +  ·  + 简体中文 +

Thank you for your interest in contributing to `GPUMDkit`! We appreciate your time and effort in helping improve this toolkit. `GPUMDkit` is an open-source package, and we welcome contributions from the community, whether you're fixing bugs, adding new features, improving documentation, or suggesting enhancements. @@ -62,7 +67,9 @@ To maintain code quality and consistency across the project, please adhere to th ### Documentation - Ensure that help messages (e.g., `-h` flags) are clear and accurate. -- Documentation files in the `docs/` directory will be updated by the maintainers, so you generally don't need to modify them. +- Tutorial documentation lives in `docs/tutorials/en/` (English) and `docs/tutorials/zh/` (Chinese). + If you add a new feature, consider updating the relevant tutorial page. +- After editing tutorial markdown files, rebuild the HTML with `mkdocs build -f docs/mkdocs.yml`. --- @@ -124,7 +131,8 @@ Name your branch as you prefer. The structure of `GPUMDkit` consists of: - **`gpumdkit.sh`**: Main entry point (Bash script) handling both interactive menu mode and command-line mode -- **`Scripts/`**: Python utility scripts organized by functionality +- **`install.sh`**: Installation script that sets up environment variables and shell configuration +- **`Scripts/`**: Python and Bash implementation scripts organized by functionality - `plt_scripts/`: Plotting scripts - `calculators/`: Calculation utilities - `format_conversion/`: Format conversion tools @@ -140,7 +148,12 @@ The structure of `GPUMDkit` consists of: - `f5_analyzers.sh` - `f6_plots.sh` - `f7_utilities.sh` +- **`skills/`**: AI agent skill definitions (SKILL.md files for opencode/Claude Code integration) - **`docs/`**: Documentation files + - `tutorials/en/` and `tutorials/zh/`: Bilingual tutorial pages + - `mkdocs.yml`: MkDocs configuration for building tutorial HTML + - `command_reference.tsv`: Machine-readable command reference + - `htmls/`: Generated HTML output from MkDocs #### Interactive Mode Contributions @@ -163,18 +176,18 @@ To add a new feature accessible through the interactive menu: Add a new function: ```bash - function f106_new_converter(){ + function f111_new_converter(){ echo " >-------------------------------------------------<" echo " | Calling the script in Scripts/format_conversion |" echo " | Script: new_converter.py |" echo " | Developer: Your Name (your@email.com) |" echo " >-------------------------------------------------<" - echo " Input the required parameters:" - echo " Examp: input.xyz output.lmp" + echo " Input " + echo " Example: input.xyz output.lmp" echo " ------------>>" - read -p " " converter_params + read -r -a converter_args echo " ---------------------------------------------------" - python ${GPUMDkit_path}/Scripts/format_conversion/new_converter.py ${converter_params} + python ${GPUMDkit_path}/Scripts/format_conversion/new_converter.py "${converter_args[@]}" echo " Code path: ${GPUMDkit_path}/Scripts/format_conversion/new_converter.py" echo " ---------------------------------------------------" } @@ -185,7 +198,7 @@ To add a new feature accessible through the interactive menu: # Find the menu() function and update it if needed # Find the array_choice array and add your new choice number array_choice=( - "0" "1" "101" "102" "103" "104" "105" "106" # Added "106" + "0" "1" "101" "102" "103" "104" "105" "106" "107" "108" "109" "110" "111" # Added "111" # ... rest of choices ) ``` @@ -199,9 +212,9 @@ To add a new feature accessible through the interactive menu: source ${GPUMDkit_path}/src/f1_format_conversions.sh case $choice in "1") f1_format_conversion ;; - "101") f101_out2xyz ;; - # ... existing cases ... - "106") f106_new_converter ;; # Add your case + "101") f101_out2xyz ;; + # ... existing cases ... + "111") f111_new_converter ;; # Add your case esac ;; # ... esac @@ -222,36 +235,35 @@ To add a new command-line flag or subcommand: # Example: Scripts/analyzer/analyze_bonds.py import sys - def main(): - if len(sys.argv) != 3: - print("Usage: gpumdkit.sh -analyze_bonds ") - print("Example: gpumdkit.sh -analyze_bonds structure.xyz 3.0") - sys.exit(1) - - input_file = sys.argv[1] - cutoff = float(sys.argv[2]) - - # Your implementation here - - if __name__ == "__main__": - main() + if len(sys.argv) != 3: + print("Usage: gpumdkit.sh -analyze_bonds ") + print("Example: gpumdkit.sh -analyze_bonds structure.xyz 3.0") + sys.exit(1) + + input_file = sys.argv[1] + cutoff = float(sys.argv[2]) + + # Your implementation here ``` + + > **Note**: GPUMDkit Python scripts are designed to run directly (not imported as modules). + > You may use a `main()` function with `if __name__ == "__main__":` guard if you prefer, + > but it is not required. Most existing scripts execute at module level. 3. **Add the command-line flag handler** in `gpumdkit.sh`: ```bash - # Find the command-line parsing section (after line ~167) + # Find the command-line parsing section (the large "case $1 in" block) # Add your new flag in the appropriate location case $1 in # ... existing cases ... -analyze_bonds) - if [ ! -z "$2" ] && [ ! -z "$3" ]; then - python ${analyzer_path}/analyze_bonds.py "$2" "$3" + if [ ! -z "$2" ] && [ "$2" != "-h" ] && [ ! -z "$3" ]; then + python ${analyzer_path}/analyze_bonds.py $2 $3 else echo " Usage: gpumdkit.sh -analyze_bonds " echo " Example: gpumdkit.sh -analyze_bonds structure.xyz 3.0" echo " Code path: ${analyzer_path}/analyze_bonds.py" - exit 1 fi ;; # ... rest of cases ... esac @@ -279,17 +291,23 @@ vim Scripts/utils/completion.sh Add your new flag to the `opts` variable: ```bash # Find the line with local opts=... -local opts="-h -update -U -help -clean -time -plt -calc -analyze_bonds -range -out2xyz ..." -# ^^^^^^^^^^^^^^ Add your flag here +local opts="-h -help -update -U -clean -time -plt -calc ... -your_new_flag ..." +# Add your flag here ``` -If your flag accepts secondary options (like `-plt` or `-calc`), add a case for it: +If your flag requires file arguments, add it to the existing file-completion case: +```bash +# Find the case for file-requiring flags and add yours with | +-out2xyz|-out2exyz|-...|-your_new_flag) + COMPREPLY=($(compgen -f -- "$cur")) ;; +``` + +If your flag accepts secondary options (like `-plt` or `-calc`), add a new case: ```bash case "$prev" in # ... existing cases ... - -analyze_bonds) - COMPREPLY=($(compgen -f -- "$cur")) # Complete with filenames - ;; + -your_new_flag) + COMPREPLY=($(compgen -W "option1 option2 option3" -- "$cur")) ;; # ... rest of cases ... esac ``` @@ -298,15 +316,53 @@ esac - **Shell Scripts**: - Use `${variable}` for variable expansion - - Write code that is clear and easy to maintain + - Use `[ ! -z "$var" ]` for non-empty checks (project convention) + - Interactive functions should follow the banner format: + ```bash + echo " >-------------------------------------------------<" + echo " | Calling the script in Scripts/ |" + echo " | Script: .py |" + echo " | Developer: () |" + echo " >-------------------------------------------------<" + ``` + - Use `read -r -a varname` for multi-word input, then pass with `"${varname[@]}"` + - Shell scripts in `src/` should start with a file header block: + ```bash + # ============================================================ + # GPUMDkit module + # Repository: https://github.com/zhyan0603/GPUMDkit + # Author: () + # ============================================================ + ``` - **Python Scripts**: - Write clear, maintainable code - Use meaningful variable names + - Use `sys.argv` for argument parsing (consistent with most existing scripts) + - Provide clear usage messages with `print("Usage: ...")` and `print("Example: ...")` + - If your script uses heavy/special packages (`NepTrain`, `calorine`, `dpdata`), add a + `print_dependency_notice()` function to inform users about citation recommendations ### Testing Your Changes -Before submitting your contribution: +Before submitting your contribution, run the relevant validation commands: + +```bash +# Shell syntax checks (always run these) +bash -n gpumdkit.sh +find src Scripts -name '*.sh' -exec bash -n {} + + +# Python syntax checks (for modified Python files) +python3 -m py_compile path/to/modified_script.py + +# MkDocs build (if you modified documentation) +mkdocs build -f docs/mkdocs.yml + +# Check for trailing whitespace issues +git diff --check +``` + +Then test functionality: 1. **Test interactive mode** (if applicable): ```bash @@ -345,10 +401,10 @@ Write clear, descriptive commit messages that explain what you changed. There ar git commit -m "your descriptive message" ``` -2. **Keep your branch updated** with the upstream `main` branch: +2. **Keep your branch updated** with the latest `dev` branch: ```bash - git fetch upstream - git rebase upstream/main + git fetch origin + git rebase origin/dev ``` 3. **Push your branch** to your fork: diff --git a/README.md b/README.md index 0f7596f..a61e5c8 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@

English  ·  - 简体中文 + 简体中文  ·  Website  ·  - Documentation + Documentation  ·  Gallery   @@ -102,7 +102,7 @@ There are two options, *interactive mode* and *command-line mode* | |_| | __/| |_| | | | | |_| | <| | |_ \____|_| \___/|_| |_|____/|_|\_\_|\__| - GPUMDkit Version 1.5.5 (dev) (2026-05-10) + GPUMDkit Version 1.5.6 (dev) (2026-06-17) Core Developer: Zihan YAN (yanzihan@westlake.edu.cn) Main Contributors: Denan LI, Xin WU, Zhoulin LIU & Chen HUA @@ -110,7 +110,7 @@ There are two options, *interactive mode* and *command-line mode* 1) Format Conversion 2) Sample Structures 3) Workflow 4) Calculators 5) Analyzer 6) Visualization - 7) Utilities 8) Developing... + 7) Utilities 8) Help 0) Exit ------------>> Input the function number: @@ -132,7 +132,7 @@ the help information: ``` +-------------------------------------------------------------------------------------------------------+ -| GPUMDkit 1.5.5 (dev) (2026-05-10) Command Help | +| GPUMDkit 1.5.6 (dev) (2026-06-17) Command Help | +-------------------------------------------------------------------------------------------------------+ | MAIN FUNCTIONS | +-------------------------------------------------------------------------------------------------------+ @@ -158,8 +158,8 @@ the help information: | -chem_species Analyze chemical species | -cbc Charge balance check | | -min_dist Min distance (no PBC) | -min_dist_pbc Min distance with PBC | | -filter_dist Filter by min_dist (no PBC) | -filter_dist_pbc Filter by min_dist (PBC) | -| -pda Probability density analysis | -hbond Hydrogen-bond analysis | -| -pynep FPS sampling by PyNEP | | +| -pda Probability density analysis | -filter_box Filter by box-edge length | +| -pynep Deprecated PyNEP sampling | -nep_modifier Modify NEP model interactively | +-------------------------------------------------------------------------------------------------------+ | Detailed usage: gpumdkit.sh -

` | | POSCAR | extxyz | `gpumdkit.sh -pos2exyz ` | | extxyz | POSCAR | `gpumdkit.sh -exyz2pos ` | -| POSCAR | LAMMPS | `gpumdkit.sh -pos2lmp ` | +| POSCAR | LAMMPS | `gpumdkit.sh -pos2lmp ` | | XDATCAR | extxyz | `gpumdkit.sh -xdat2exyz XDATCAR dump.xyz` | | LAMMPS dump | extxyz | `gpumdkit.sh -lmp2exyz ` | -| CIF | extxyz | `gpumdkit.sh -cif2exyz ` | -| CIF | POSCAR | `gpumdkit.sh -cif2pos ` | +| CIF | extxyz | `gpumdkit.sh -cif2exyz ` | +| CIF | POSCAR | `gpumdkit.sh -cif2pos ` | | Add groups | - | `gpumdkit.sh -addgroup ` | | Add weight | - | `gpumdkit.sh -addweight ` | | Replicate1 | - | `gpumdkit.sh -replicate input.vasp output.vasp 2 2 2` | | Replicate2 | - | `gpumdkit.sh -replicate input.vasp output.vasp ` | | Get frame | - | `gpumdkit.sh -get_frame ` | +| Clean extxyz | - | `gpumdkit.sh -clean_xyz ` | +| ASE traj | extxyz | `gpumdkit.sh -traj2exyz ` | --- @@ -82,8 +84,8 @@ This script adds weight labels to structures. python add_weight.py ``` -- ``: The path to the input file (e.g., train.xyz). -- ``: The path to the input file (e.g., train_weighted.xyz). +- ``: The path to the input file (e.g., train.xyz). +- ``: The path to the output file (e.g., train_weighted.xyz). - ``: The `weight` you need to change. #### Example @@ -208,6 +210,112 @@ This command will split all frames in `extxyz_file` into separate files named `m +### out2exyz.py + +--- + +This script searches a directory for VASP `OUTCAR` files and writes the converged configurations to `train.xyz` in extxyz format. + +#### Usage + +``` +python out2exyz.py +``` + +#### Example + +```sh +python out2exyz.py ./ +``` + +#### Command-Line Mode Example + +``` +gpumdkit.sh -out2exyz ./ +``` + +The output file is `train.xyz`. + + + +### cif2pos.py + +--- + +This script converts a CIF file to VASP POSCAR format. + +#### Usage + +``` +python cif2pos.py +``` + +#### Example + +```sh +python cif2pos.py input.cif POSCAR.vasp +``` + +#### Command-Line Mode Example + +``` +gpumdkit.sh -cif2pos input.cif POSCAR.vasp +``` + + + +### cif2exyz.py + +--- + +This script converts a CIF file to extxyz format. + +#### Usage + +``` +python cif2exyz.py +``` + +#### Example + +```sh +python cif2exyz.py input.cif model.xyz +``` + +#### Command-Line Mode Example + +``` +gpumdkit.sh -cif2exyz input.cif model.xyz +``` + + + +### xdatcar2exyz.py + +--- + +This script converts a VASP `XDATCAR` trajectory to extxyz format. + +#### Usage + +``` +python xdatcar2exyz.py +``` + +#### Example + +```sh +python xdatcar2exyz.py XDATCAR dump.xyz +``` + +#### Command-Line Mode Example + +``` +gpumdkit.sh -xdat2exyz XDATCAR dump.xyz +``` + + + ### lmp2exyz.py --- @@ -243,7 +351,7 @@ It will convert the `dump.data` to `dump.xyz` file --- -This script will read the `extxyz` file and return the specified frame by index.. +This script will read the `extxyz` file and return the specified frame by index. #### Usage @@ -270,6 +378,58 @@ You will get the `frame_1000.xyz` file after perform the script. +### clean_xyz.py + +--- + +This script removes stress, virial, force, and calculator result information from an extxyz file and writes the cleaned structures to a new extxyz file. + +#### Usage + +``` +python clean_xyz.py +``` + +#### Example + +```sh +python clean_xyz.py train.xyz train_clean.xyz +``` + +#### Command-Line Mode Example + +``` +gpumdkit.sh -clean_xyz train.xyz train_clean.xyz +``` + + + +### traj2exyz.py + +--- + +This script converts an ASE `.traj` file to extxyz format. + +#### Usage + +``` +python traj2exyz.py +``` + +#### Example + +```sh +python traj2exyz.py input.traj output.xyz +``` + +#### Command-Line Mode Example + +``` +gpumdkit.sh -traj2exyz input.traj output.xyz +``` + + + ## Contributing To add new format converters: @@ -277,7 +437,7 @@ To add new format converters: 1. **Follow naming**: `2.py` 2. **Handle errors**: Validate input format before processing 3. **Document**: Add usage to this README -6. **Update gpumdkit.sh**: Add command-line flag if appropriate +4. **Update gpumdkit.sh**: Add command-line flag if appropriate See [CONTRIBUTING.md](../../CONTRIBUTING.md) for detailed guidelines. diff --git a/Scripts/format_conversion/abacus2xyz_md.sh b/Scripts/format_conversion/abacus2xyz_md.sh index 4032903..50c1823 100644 --- a/Scripts/format_conversion/abacus2xyz_md.sh +++ b/Scripts/format_conversion/abacus2xyz_md.sh @@ -3,7 +3,7 @@ # GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP # Repository: https://github.com/zhyan0603/GPUMDkit # Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, -# MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) +# MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) # ============================================================================= # Script: abacus2xyz_md.sh # Category: Format Conversion Scripts diff --git a/Scripts/format_conversion/abacus2xyz_scf.py b/Scripts/format_conversion/abacus2xyz_scf.py index 07b8051..28431a3 100644 --- a/Scripts/format_conversion/abacus2xyz_scf.py +++ b/Scripts/format_conversion/abacus2xyz_scf.py @@ -3,12 +3,13 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: abacus2xyz_scf.py Category: Format Conversion Scripts Purpose: Convert ABACUS SCF output files to extended XYZ format. Usage: python abacus2xyz_scf.py + (invoked interactively via gpumdkit.sh menu 104) Arguments: dir Directory containing ABACUS SCF outputs extxyz Output extxyz file @@ -25,7 +26,8 @@ def main(): if len(sys.argv) != 3: - print("Usage: python abacus2xyz_scf.py ") + print(" Usage: python abacus2xyz_scf.py ") + print(" (invoked interactively via gpumdkit.sh menu 104)") sys.exit(1) if __name__ == "__main__": main() @@ -110,4 +112,3 @@ def get_scf_info(root): for i in range(natoms): f.write(f"{symbols[i]:<20}{positions[i][0]:20.10f}{positions[i][1]:20.10f}{positions[i][2]:20.10f}{forces[i][0]:20.10f}{forces[i][1]:20.10f}{forces[i][2]:20.10f} \n") print(f" Successfully converted structure in {root} to extxyz format") - diff --git a/Scripts/format_conversion/abacus2xyz_scf.sh b/Scripts/format_conversion/abacus2xyz_scf.sh index 3428e3a..5b6614f 100644 --- a/Scripts/format_conversion/abacus2xyz_scf.sh +++ b/Scripts/format_conversion/abacus2xyz_scf.sh @@ -3,7 +3,7 @@ # GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP # Repository: https://github.com/zhyan0603/GPUMDkit # Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, -# MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) +# MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) # ============================================================================= # Script: abacus2xyz_scf.sh # Category: Format Conversion Scripts diff --git a/Scripts/format_conversion/add_groups.py b/Scripts/format_conversion/add_groups.py index c0bcd2f..221ff9a 100644 --- a/Scripts/format_conversion/add_groups.py +++ b/Scripts/format_conversion/add_groups.py @@ -3,24 +3,44 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: add_groups.py Category: Format Conversion Scripts Purpose: Add group information to atoms in a structure file based on - element types, outputting the result to stdout. -Usage: python add_groups.py ... + element types, outputting the result to model.xyz. +Usage: gpumdkit.sh -addgroup ... + gpumdkit.sh -addlabel ... + python add_groups.py ... Arguments: input.xyz Input structure file elementX Element symbols to assign group indices Output: - Modified structure with group information (printed to stdout) + model.xyz Structure with group information Author: Zihan YAN (yanzihan@westlake.edu.cn) Last-modified: 2026-05-16 ============================================================================= """ import sys + +args = sys.argv[1:] +if len(args) < 2 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -addgroup ...") + print(" gpumdkit.sh -addlabel ...") + print(" or: python add_groups.py ...") + print("") + print(" Arguments:") + print(" input.xyz Input structure file") + print(" elementX Element symbols to assign group indices (in order)") + print("") + print(" Output:") + print(" model.xyz Structure with group information") + print("") + print(" Example: gpumdkit.sh -addgroup POSCAR Li Ti O") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + from ase.io import read, write import numpy as np diff --git a/Scripts/format_conversion/add_weight.py b/Scripts/format_conversion/add_weight.py index ff3841b..7b7492b 100644 --- a/Scripts/format_conversion/add_weight.py +++ b/Scripts/format_conversion/add_weight.py @@ -3,13 +3,14 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: add_weight.py Category: Format Conversion Scripts Purpose: Add a weight value to the 'Weight' attribute of each structure in an input file and save the modified structures. -Usage: python add_weight.py +Usage: gpumdkit.sh -addweight + python add_weight.py Arguments: input_file Input structure file output_file Output structure file with added weight @@ -23,14 +24,24 @@ import os import sys + +args = sys.argv[1:] +if len(args) < 3 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -addweight ") + print(" or: python add_weight.py ") + print("") + print(" Arguments:") + print(" input.xyz Input extxyz file") + print(" output.xyz Output extxyz file with added weight") + print(" weight Weight value to assign (e.g., 1.0)") + print("") + print(" Example: gpumdkit.sh -addweight train.xyz weighted.xyz 2.0") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + from ase.io import read, write def main(): - # Check if the correct number of arguments are provided - if len(sys.argv) != 4: - print("Usage: python script.py ") - sys.exit(1) - # Parse command line arguments input_file = sys.argv[1] output_file = sys.argv[2] diff --git a/Scripts/format_conversion/cif2exyz.py b/Scripts/format_conversion/cif2exyz.py index 6b0ac7c..687959d 100644 --- a/Scripts/format_conversion/cif2exyz.py +++ b/Scripts/format_conversion/cif2exyz.py @@ -3,12 +3,13 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: cif2exyz.py Category: Format Conversion Scripts Purpose: Convert CIF file to extended XYZ format using ASE. -Usage: python cif2exyz.py +Usage: gpumdkit.sh -cif2exyz + python cif2exyz.py Arguments: input.cif Input CIF file output.xyz Output extxyz file @@ -20,12 +21,21 @@ """ import sys -from ase.io import read, write -# Check command line arguments -if len(sys.argv) != 3: - print(" Usage: python cif2exyz.py input.cif output.xyz") - sys.exit(1) +args = sys.argv[1:] +if len(args) < 2 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -cif2exyz ") + print(" or: python cif2exyz.py ") + print("") + print(" Arguments:") + print(" input.cif Input CIF file") + print(" output.xyz Output extxyz file") + print("") + print(" Example: gpumdkit.sh -cif2exyz structure.cif output.xyz") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + +from ase.io import read, write # Read input and output file paths cif_file = sys.argv[1] diff --git a/Scripts/format_conversion/cif2pos.py b/Scripts/format_conversion/cif2pos.py index 8657fc6..238e999 100644 --- a/Scripts/format_conversion/cif2pos.py +++ b/Scripts/format_conversion/cif2pos.py @@ -3,12 +3,13 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: cif2pos.py Category: Format Conversion Scripts Purpose: Convert CIF file to VASP POSCAR format using ASE. -Usage: python cif2pos.py +Usage: gpumdkit.sh -cif2pos + python cif2pos.py Arguments: input.cif Input CIF file output.vasp Output VASP POSCAR file @@ -20,12 +21,21 @@ """ import sys -from ase.io import read, write -# Check command line arguments -if len(sys.argv) != 3: - print(" Usage: python cif2poscar.py input.cif output.vasp") - sys.exit(1) +args = sys.argv[1:] +if len(args) < 2 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -cif2pos ") + print(" or: python cif2pos.py ") + print("") + print(" Arguments:") + print(" input.cif Input CIF file") + print(" output.vasp Output VASP POSCAR file") + print("") + print(" Example: gpumdkit.sh -cif2pos structure.cif POSCAR") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + +from ase.io import read, write # Read input and output file paths cif_file = sys.argv[1] diff --git a/Scripts/format_conversion/clean_xyz.py b/Scripts/format_conversion/clean_xyz.py index 2ae4e97..3060116 100644 --- a/Scripts/format_conversion/clean_xyz.py +++ b/Scripts/format_conversion/clean_xyz.py @@ -3,16 +3,17 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: clean_xyz.py Category: Format Conversion Scripts Purpose: Remove stress, virial, and force information from an extxyz training file, keeping only structural information. -Usage: python clean_xyz.py [output.xyz] +Usage: gpumdkit.sh -clean_xyz + python clean_xyz.py Arguments: input.xyz Input extxyz training file - output.xyz Output cleaned extxyz file (optional) + output.xyz Output cleaned extxyz file Output: Cleaned extxyz file with only structural information Author: Zihan YAN (yanzihan@westlake.edu.cn) @@ -20,9 +21,27 @@ ============================================================================= """ -from ase.io import read, write import sys +args = sys.argv[1:] +if len(args) < 2 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -clean_xyz ") + print(" or: python clean_xyz.py ") + print("") + print(" Arguments:") + print(" input.xyz Input extxyz training file") + print(" output.xyz Output cleaned extxyz file") + print("") + print(" Output:") + print(" Cleaned extxyz file with only structural information") + print(" (stress, virial, and force data are removed)") + print("") + print(" Example: gpumdkit.sh -clean_xyz train.xyz cleaned.xyz") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + +from ase.io import read, write + # Read all frames from the input train.xyz file frames = read(sys.argv[1], index=':') @@ -50,3 +69,4 @@ # Export the cleaned frames to a new extxyz file, containing only lattice and atomic information write(sys.argv[2], frames, format='extxyz') +print(f" Cleaned {len(frames)} frames, saved to {sys.argv[2]}") diff --git a/Scripts/format_conversion/cp2k2xyz.py b/Scripts/format_conversion/cp2k2xyz.py index ca10567..01238fd 100644 --- a/Scripts/format_conversion/cp2k2xyz.py +++ b/Scripts/format_conversion/cp2k2xyz.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: cp2k2xyz.py Category: Format Conversion Scripts diff --git a/Scripts/format_conversion/cp2k_log2xyz.py b/Scripts/format_conversion/cp2k_log2xyz.py index e88ed24..65c73ba 100644 --- a/Scripts/format_conversion/cp2k_log2xyz.py +++ b/Scripts/format_conversion/cp2k_log2xyz.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: cp2k_log2xyz.py Category: Format Conversion Scripts @@ -42,7 +42,7 @@ def extract_atoms_lattice_xyz(lines): if m := re.search(r'Lattice="([^"]+)"', '\n'.join(lines)): lat = [float(x) for x in m.group(1).split()] return atoms, lat - except: return [], [] + except (ValueError, IndexError): return [], [] def extract_atoms_lattice_inp(text): atoms, lat = [], [0.0]*9 diff --git a/Scripts/format_conversion/dp2xyz.py b/Scripts/format_conversion/dp2xyz.py new file mode 100644 index 0000000..7f434e4 --- /dev/null +++ b/Scripts/format_conversion/dp2xyz.py @@ -0,0 +1,96 @@ +""" +============================================================================= +GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP +Repository: https://github.com/zhyan0603/GPUMDkit +Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) +============================================================================= +Script: dp2xyz.py +Category: Format Conversion Scripts +Purpose: Convert DeepMD npy datasets under a directory to extended XYZ + format using dpdata. Recursively finds type.raw + set.000 + directories and converts all frames into a single extxyz file. +Usage: gpumdkit.sh -dp2xyz [output.xyz] + python3 dp2xyz.py [output.xyz] +Arguments: + input_dir/ Directory to scan recursively for DeepMD npy datasets + output.xyz Output extxyz file (default: train.xyz) +Output: + (converted structures in extxyz format) +Author: Denan LI (lidenan@westlake.edu.cn) +Last-modified: 2026-07-01 +============================================================================= +""" + +import os +import sys + +args = sys.argv[1:] +if len(args) < 1 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -dp2xyz [output.xyz]") + print(" or: python3 dp2xyz.py [output.xyz]") + print("") + print(" Arguments:") + print(" input_dir/ Directory to scan recursively for DeepMD npy datasets") + print(" output.xyz Output extxyz file (default: train.xyz)") + print("") + print(" Example: gpumdkit.sh -dp2xyz database train.xyz") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + +import dpdata +from ase.io import write + + +def is_deepmd_npy_dataset(path): + return ( + os.path.isfile(os.path.join(path, "type.raw")) + and os.path.isfile(os.path.join(path, "type_map.raw")) + and os.path.isdir(os.path.join(path, "set.000")) + ) + + +def find_deepmd_npy_datasets(input_dir): + dataset_dirs = [] + for root, dirs, _ in os.walk(input_dir): + dirs.sort() + if is_deepmd_npy_dataset(root): + dataset_dirs.append(root) + return dataset_dirs + + +if __name__ == "__main__": + input_dir = args[0] + output_file = args[1] if len(args) == 2 else "train.xyz" + + if not os.path.isdir(input_dir): + print(f" Error: input directory '{input_dir}' does not exist.") + sys.exit(1) + + dataset_dirs = find_deepmd_npy_datasets(input_dir) + if not dataset_dirs: + print(f" Error: no DeepMD npy datasets found under {input_dir}") + sys.exit(1) + + all_frames = [] + print(f" Found {len(dataset_dirs)} DeepMD npy dataset(s) under {input_dir}") + + for dataset_dir in dataset_dirs: + try: + system = dpdata.LabeledSystem(dataset_dir, fmt="deepmd/npy") + except Exception as e: + print(f" Error: failed to load {dataset_dir}: {e}") + sys.exit(1) + + frames = system.to_ase_structure() + all_frames.extend(frames) + print(f" Loaded {len(frames)} frames from {dataset_dir}") + + try: + write(output_file, all_frames, format="extxyz", append=False) + except Exception as e: + print(f" Error: failed to write {output_file}: {e}") + sys.exit(1) + + print(f" Converted {len(all_frames)} frames from {len(dataset_dirs)} dataset(s)") + print(f" Saved extxyz file to {output_file}") diff --git a/Scripts/format_conversion/exyz2lmp.py b/Scripts/format_conversion/exyz2lmp.py index f9e6d2b..6d857c8 100644 --- a/Scripts/format_conversion/exyz2lmp.py +++ b/Scripts/format_conversion/exyz2lmp.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: exyz2lmp.py Category: Format Conversion Scripts @@ -21,9 +21,25 @@ """ import sys -from ase.io import read, write + + +def print_usage(): + print(" Usage: python exyz2lmp.py ") + print("") + print(" Arguments:") + print(" extxyz_file Input extxyz file") + print(" lammps_data_file Output LAMMPS data file") + print("") + print(" Output:") + print(" ") + print("") + print(" Example: python exyz2lmp.py model.xyz data.lammps") + print("") + def convert_extxyz_to_lammps_data(extxyz_file, lammps_data_file): + from ase.io import read + # Read the EXTXYZ file atoms = read(extxyz_file, format='extxyz') @@ -65,15 +81,14 @@ def convert_extxyz_to_lammps_data(extxyz_file, lammps_data_file): atom_type = symbol_to_type[atom.symbol] x, y, z = atom.position f.write(f"{atom_id} {atom_type} {x} {y} {z}\n") - -# print(f"Conversion complete! {extxyz_file} has been converted to {lammps_data_file}") if __name__ == '__main__': - if len(sys.argv) != 3: - print("Usage: python exyz2lmp.py ") - sys.exit(1) + args = sys.argv[1:] + if len(args) != 2 or args[0] in ("-h", "--help"): + print_usage() + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) - extxyz_file = sys.argv[1] - lammps_data_file = sys.argv[2] + extxyz_file = args[0] + lammps_data_file = args[1] convert_extxyz_to_lammps_data(extxyz_file, lammps_data_file) diff --git a/Scripts/format_conversion/exyz2pos.py b/Scripts/format_conversion/exyz2pos.py index 092f680..edb037c 100644 --- a/Scripts/format_conversion/exyz2pos.py +++ b/Scripts/format_conversion/exyz2pos.py @@ -3,22 +3,39 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: exyz2pos.py Category: Format Conversion Scripts Purpose: Convert extended XYZ file(s) to VASP POSCAR format(s). -Usage: python exyz2pos.py [extxyz_file] +Usage: gpumdkit.sh -exyz2pos + python exyz2pos.py Arguments: - extxyz_file Input extxyz file (default: train.xyz) + input.xyz Input extxyz file Output: - POSCAR file(s) in VASP format + POSCAR_*.vasp POSCAR file(s) in VASP format (one per frame) Author: Zihan YAN (yanzihan@westlake.edu.cn) Last-modified: 2026-05-16 ============================================================================= """ import sys + +args = sys.argv[1:] +if len(args) < 1 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -exyz2pos ") + print(" or: python exyz2pos.py ") + print("") + print(" Arguments:") + print(" input.xyz Input extxyz trajectory file") + print("") + print(" Output:") + print(" POSCAR_*.vasp POSCAR file(s) in VASP format (one per frame)") + print("") + print(" Example: gpumdkit.sh -exyz2pos train.xyz") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + from ase.io import read, write def print_progress_bar(iteration, total, length=50): @@ -30,7 +47,7 @@ def print_progress_bar(iteration, total, length=50): if iteration == total: print() -input_file = sys.argv[1] if len(sys.argv) > 1 else 'train.xyz' +input_file = sys.argv[1] # Read all frames frames = read(input_file, index=':') @@ -42,4 +59,4 @@ def print_progress_bar(iteration, total, length=50): write(poscar_filename, frame) print_progress_bar(i + 1, total_frames) -print(f' All frames have been converted.') \ No newline at end of file +print(f' All frames have been converted.') diff --git a/Scripts/format_conversion/get_frame.py b/Scripts/format_conversion/get_frame.py index 23e9971..5dbb08e 100644 --- a/Scripts/format_conversion/get_frame.py +++ b/Scripts/format_conversion/get_frame.py @@ -3,12 +3,13 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: get_frame.py Category: Format Conversion Scripts Purpose: Extract a single frame from an extxyz trajectory by frame number. -Usage: python get_frame.py +Usage: gpumdkit.sh -get_frame + python get_frame.py Arguments: input.xyz Input extxyz trajectory file frame_number Frame number to extract (1-indexed) @@ -20,6 +21,23 @@ """ import sys + +args = sys.argv[1:] +if len(args) < 2 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -get_frame ") + print(" or: python get_frame.py ") + print("") + print(" Arguments:") + print(" input.xyz Input extxyz trajectory file") + print(" frame_number Frame number to extract (1-indexed)") + print("") + print(" Output:") + print(" frame_.xyz Extracted single frame") + print("") + print(" Example: gpumdkit.sh -get_frame train.xyz 10") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + from ase.io import read, write def get_frame(): diff --git a/Scripts/format_conversion/lmp2exyz.py b/Scripts/format_conversion/lmp2exyz.py index 4533a91..450aab5 100644 --- a/Scripts/format_conversion/lmp2exyz.py +++ b/Scripts/format_conversion/lmp2exyz.py @@ -3,24 +3,42 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: lmp2exyz.py Category: Format Conversion Scripts Purpose: Convert LAMMPS dump file to extended XYZ format with proper element type mapping. -Usage: python lmp2exyz.py ... +Usage: gpumdkit.sh -lmp2exyz ... + python lmp2exyz.py ... Arguments: dump_file Input LAMMPS dump file elementX Chemical element symbols in order of atomic types Output: - Converted structures in extxyz format + dump.xyz Converted structures in extxyz format Author: Zihan YAN (yanzihan@westlake.edu.cn) Last-modified: 2026-05-16 ============================================================================= """ import sys + +args = sys.argv[1:] +if len(args) < 2 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -lmp2exyz ...") + print(" or: python lmp2exyz.py ...") + print("") + print(" Arguments:") + print(" dump_file Input LAMMPS dump file") + print(" elementX Chemical element symbols in order of atomic types") + print("") + print(" Output:") + print(" dump.xyz Converted structures in extxyz format") + print("") + print(" Example: gpumdkit.sh -lmp2exyz dump.lammps Si O") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + from ase.io import read, write def lmp2exyz(dump_file, elements): @@ -44,14 +62,9 @@ def lmp2exyz(dump_file, elements): # Write to extxyz file extxyz_file = 'dump.xyz' write(extxyz_file, frames, format='extxyz') -# print(f" Converted {dump_file} to {extxyz_file}") if __name__ == '__main__': - if len(sys.argv) < 3: - print(" Usage: python lmp2exyz.py ...") - sys.exit(1) - dump_file = sys.argv[1] elements = sys.argv[2:] - + lmp2exyz(dump_file, elements) diff --git a/Scripts/format_conversion/mtp2xyz.py b/Scripts/format_conversion/mtp2xyz.py index dd2d840..fd226e0 100644 --- a/Scripts/format_conversion/mtp2xyz.py +++ b/Scripts/format_conversion/mtp2xyz.py @@ -3,18 +3,19 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: mtp2xyz.py Category: Format Conversion Scripts Purpose: Convert MTP (Machine Learning Interatomic Potential) input file - format to extended XYZ using dpdata. -Usage: python mtp2xyz.py ... + format to extended XYZ using a custom cfg parser and ASE. +Usage: Interactive: gpumdkit.sh -> 1 -> 102 + python mtp2xyz.py ... Arguments: train.cfg MTP training data file SymbolX Chemical element symbols in order Output: - Converted structure in extxyz format (printed to terminal or saved) + XYZ/mtp2xyz.xyz Converted structures in extxyz format Author: Ke XU (kickhsu@gmail.com) Last-modified: 2026-05-16 ============================================================================= @@ -132,6 +133,11 @@ def dump_xyz(frames): if __name__ == "__main__": + # Check arguments + if len(sys.argv) < 3: + print(" Usage: python mtp2xyz.py ...") + sys.exit(1) + type_to_symbol = {i: s for i, s in enumerate(sys.argv[2:])} frames = load_cfg(sys.argv[1], type_to_symbol) #dump_nep(frames) diff --git a/Scripts/format_conversion/out2exyz.py b/Scripts/format_conversion/out2exyz.py index a46cf4f..5451c3d 100644 --- a/Scripts/format_conversion/out2exyz.py +++ b/Scripts/format_conversion/out2exyz.py @@ -3,21 +3,40 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: out2exyz.py Category: Format Conversion Scripts Purpose: Convert VASP OUTCAR files to extended XYZ format with energy, - forces, stress, and virial information. -Usage: python out2exyz.py [directory with OUTCARs] + forces, and virial information. +Usage: gpumdkit.sh -out2exyz + python out2exyz.py +Arguments: + directory Root directory to search for OUTCAR files Output: - Converted structures in extxyz format + train.xyz Converted structures in extxyz format Author: Zihan YAN (yanzihan@westlake.edu.cn) Last-modified: 2026-05-16 ============================================================================= """ import os, sys + +args = sys.argv[1:] +if len(args) < 1 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -out2exyz ") + print(" or: python out2exyz.py ") + print("") + print(" Arguments:") + print(" directory Root directory to search for OUTCAR files") + print("") + print(" Output:") + print(" train.xyz Converted structures in extxyz format") + print("") + print(" Example: gpumdkit.sh -out2exyz .") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + import numpy as np from ase.io import read, write from ase import Atoms, Atom @@ -101,7 +120,7 @@ def is_converged(outcar_path): try: atoms = read(file_path, format='vasp-out', index=":") - except: + except Exception: err_list.append(file_path) continue @@ -125,4 +144,4 @@ def is_converged(outcar_path): for non_conv_filename in non_converged_list: print(non_conv_filename) else: - print(" All calculations are converged!") \ No newline at end of file + print(" All calculations are converged!") diff --git a/Scripts/format_conversion/out2xyz.sh b/Scripts/format_conversion/out2xyz.sh index 8c46b64..b612524 100644 --- a/Scripts/format_conversion/out2xyz.sh +++ b/Scripts/format_conversion/out2xyz.sh @@ -3,7 +3,7 @@ # GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP # Repository: https://github.com/zhyan0603/GPUMDkit # Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, -# MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) +# MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) # ============================================================================= # Script: out2xyz.sh # Category: Format Conversion Scripts diff --git a/Scripts/format_conversion/pos2exyz.py b/Scripts/format_conversion/pos2exyz.py index 8316016..7936fc7 100644 --- a/Scripts/format_conversion/pos2exyz.py +++ b/Scripts/format_conversion/pos2exyz.py @@ -3,12 +3,13 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: pos2exyz.py Category: Format Conversion Scripts Purpose: Convert one or more VASP POSCAR files to extended XYZ format. -Usage: python pos2exyz.py +Usage: gpumdkit.sh -pos2exyz + python pos2exyz.py Arguments: POSCAR One or more VASP POSCAR files output.xyz Output extxyz file @@ -20,6 +21,20 @@ """ import sys + +args = sys.argv[1:] +if len(args) < 2 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -pos2exyz ") + print(" or: python pos2exyz.py ") + print("") + print(" Arguments:") + print(" POSCAR One or more VASP POSCAR files (supports wildcards)") + print(" output.xyz Output extxyz file") + print("") + print(" Example: gpumdkit.sh -pos2exyz POSCAR output.xyz") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + import glob from ase.io import read, write @@ -42,13 +57,6 @@ def convert_poscar_to_extxyz(poscar_filenames, extxyz_filename): write(extxyz_filename, all_frames, format='extxyz', append=False) if __name__ == '__main__': - # Check if the number of arguments is correct - if len(sys.argv) < 3: - print("Usage: python pos2exyz.py ") - print("Example 1: python pos2exyz.py POSCAR model.xyz") - # print("Example 2: python pos2exyz.py 'POSCAR*' train.xyz") - sys.exit(1) - poscar_filename_pattern = sys.argv[1] extxyz_filename = sys.argv[2] diff --git a/Scripts/format_conversion/pos2lmp.py b/Scripts/format_conversion/pos2lmp.py index b2cf10f..02b85f2 100644 --- a/Scripts/format_conversion/pos2lmp.py +++ b/Scripts/format_conversion/pos2lmp.py @@ -3,12 +3,13 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: pos2lmp.py Category: Format Conversion Scripts Purpose: Convert VASP POSCAR file to LAMMPS data format using OVITO. -Usage: python pos2lmp.py +Usage: gpumdkit.sh -pos2lmp + python pos2lmp.py Arguments: poscar_file Input VASP POSCAR file lammps_data_file Output LAMMPS data file @@ -20,6 +21,20 @@ """ import sys + +args = sys.argv[1:] +if len(args) < 2 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -pos2lmp ") + print(" or: python pos2lmp.py ") + print("") + print(" Arguments:") + print(" poscar_file Input VASP POSCAR file") + print(" lammps_data_file Output LAMMPS data file") + print("") + print(" Example: gpumdkit.sh -pos2lmp POSCAR data.lammps") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + from ovito.io import import_file, export_file def convert_poscar_to_lammps(poscar_path, lammps_data_path): @@ -28,12 +43,8 @@ def convert_poscar_to_lammps(poscar_path, lammps_data_path): export_file(pipeline, lammps_data_path, "lammps/data", multiple_frames=False) if __name__ == "__main__": - if len(sys.argv) != 3: - print("Usage: python pos2lmp.py ") - sys.exit(1) - poscar_file = sys.argv[1] lammps_data_file = sys.argv[2] - + convert_poscar_to_lammps(poscar_file, lammps_data_file) print(f" Converted {poscar_file} to {lammps_data_file} successfully.") diff --git a/Scripts/format_conversion/replicate.py b/Scripts/format_conversion/replicate.py index 36a70f4..c7a6fba 100644 --- a/Scripts/format_conversion/replicate.py +++ b/Scripts/format_conversion/replicate.py @@ -3,17 +3,20 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: replicate.py Category: Format Conversion Scripts Purpose: Replicate a unit cell to generate a supercell with a target number of atoms, finding the nearest compatible supercell size. -Usage: python replicate.py input.vasp output.vasp a b c +Usage: gpumdkit.sh -replicate input.vasp output.vasp a b c + gpumdkit.sh -replicate input.vasp output.vasp target_num + python replicate.py input.vasp output.vasp a b c python replicate.py input.vasp output.vasp target_num Arguments: input.vasp Input structure file output.vasp Output supercell file + a b c Replication factors along x, y, z axes target_n_atoms Target number of atoms in the supercell Output: (replicated supercell structure) @@ -25,6 +28,25 @@ import sys import os import math + +args = sys.argv[1:] +if len(args) not in (3, 5) or args[0] in ("-h", "--help"): + print(" Usage 1: gpumdkit.sh -replicate input.vasp output.vasp a b c") + print(" Usage 2: gpumdkit.sh -replicate input.vasp output.vasp target_num") + print(" or: python replicate.py input.vasp output.vasp a b c") + print(" or: python replicate.py input.vasp output.vasp target_num") + print("") + print(" Arguments:") + print(" input.vasp Input structure file (any ASE-supported format)") + print(" output.vasp Output supercell file") + print(" a b c Replication factors along x, y, z axes") + print(" target_num Target number of atoms (auto-finds best a,b,c)") + print("") + print(" Example: gpumdkit.sh -replicate POSCAR supercell.vasp 2 2 2") + print(" gpumdkit.sh -replicate POSCAR supercell.vasp 256") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + import numpy as np from ase.io import read, write from ase.build import make_supercell @@ -105,20 +127,16 @@ def reorder_atoms_by_input_species_order(atoms, original_atoms): return reordered_atoms def main(): - if len(sys.argv) < 4: - print(" Usage 1: python replicate.py input.vasp output.vasp a b c") - print(" Usage 2: python replicate.py input.vasp output.vasp target_num") - sys.exit(1) - infile = sys.argv[1] outfile = sys.argv[2] - args = sys.argv[3:] + args_inner = sys.argv[3:] - # Infer input/output format + # Infer input/output format from file extension + # When there is no extension (e.g. POSCAR), let ASE auto-detect in_ext = os.path.splitext(infile)[1][1:].lower() out_ext = os.path.splitext(outfile)[1][1:].lower() - in_format = "extxyz" if in_ext == "xyz" else in_ext or "extxyz" - out_format = "extxyz" if out_ext == "xyz" else out_ext or "extxyz" + in_format = "extxyz" if in_ext == "xyz" else (in_ext if in_ext else None) + out_format = "extxyz" if out_ext == "xyz" else (out_ext if out_ext else "vasp") try: atoms = read(infile, format=in_format) @@ -127,19 +145,19 @@ def main(): sys.exit(1) n_atoms = len(atoms) - - if len(args) == 1: # Target atom number + + if len(args_inner) == 1: # Target atom number try: - target_num = int(args[0]) + target_num = int(args_inner[0]) except ValueError: print(" Error: num must be an integer") sys.exit(1) a, b, c = find_nearest_supercell(atoms, target_num) total_atoms = n_atoms * a * b * c print(f"Original atoms: {n_atoms}, Target: {target_num}, Selected: {a}x{b}x{c} (total {total_atoms} atoms)") - elif len(args) == 3: # a b c + elif len(args_inner) == 3: # a b c try: - a, b, c = map(int, args) + a, b, c = map(int, args_inner) except ValueError: print(" Error: a, b, c must be integers") sys.exit(1) @@ -171,4 +189,4 @@ def main(): sys.exit(1) if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/Scripts/format_conversion/split_single_xyz.py b/Scripts/format_conversion/split_single_xyz.py index 904cdb3..3728c41 100644 --- a/Scripts/format_conversion/split_single_xyz.py +++ b/Scripts/format_conversion/split_single_xyz.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: split_single_xyz.py Category: Format Conversion Scripts @@ -45,7 +45,7 @@ def split_xyz_to_individual_models(input_xyz_filename): if __name__ == '__main__': # Check if the number of arguments is correct if len(sys.argv) < 2: - print(" Usage: python script_name.py ") + print(" Usage: python split_single_xyz.py ") sys.exit(1) # Get input XYZ filename from command line argument diff --git a/Scripts/format_conversion/traj2exyz.py b/Scripts/format_conversion/traj2exyz.py index 9eb592b..0c5beb0 100644 --- a/Scripts/format_conversion/traj2exyz.py +++ b/Scripts/format_conversion/traj2exyz.py @@ -3,12 +3,13 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: traj2exyz.py Category: Format Conversion Scripts Purpose: Convert an ASE .traj trajectory file to extended XYZ format. -Usage: python traj2exyz.py +Usage: gpumdkit.sh -traj2exyz + python traj2exyz.py Arguments: input.traj Input ASE trajectory file output.xyz Output extxyz file @@ -20,6 +21,20 @@ """ import sys + +args = sys.argv[1:] +if len(args) < 2 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -traj2exyz ") + print(" or: python traj2exyz.py ") + print("") + print(" Arguments:") + print(" input.traj Input ASE trajectory file") + print(" output.xyz Output extxyz file") + print("") + print(" Example: gpumdkit.sh -traj2exyz md.traj output.xyz") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + import os from ase.io import read, write @@ -45,11 +60,6 @@ def convert_traj_to_extxyz(input_file, output_file): print(f" An unexpected error occurred: {e}") if __name__ == "__main__": - # Check if correct number of arguments are provided - if len(sys.argv) != 3: - print(" Usage: python traj2exyz.py ") - sys.stdout.flush() - else: - input_path = sys.argv[1] - output_path = sys.argv[2] - convert_traj_to_extxyz(input_path, output_path) \ No newline at end of file + input_path = sys.argv[1] + output_path = sys.argv[2] + convert_traj_to_extxyz(input_path, output_path) \ No newline at end of file diff --git a/Scripts/format_conversion/xdatcar2exyz.py b/Scripts/format_conversion/xdatcar2exyz.py index 8b0b2a6..d0bd6f9 100644 --- a/Scripts/format_conversion/xdatcar2exyz.py +++ b/Scripts/format_conversion/xdatcar2exyz.py @@ -3,12 +3,13 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: xdatcar2exyz.py Category: Format Conversion Scripts Purpose: Convert VASP XDATCAR file to extended XYZ format using ASE. -Usage: python xdatcar2exyz.py +Usage: gpumdkit.sh -xdat2exyz + python xdatcar2exyz.py Arguments: input Path to the input XDATCAR file output Path to the output .xyz file @@ -19,39 +20,46 @@ ============================================================================= """ -import argparse import sys -from ase.io import read, write -# 1. Setup Argument Parser for positional arguments -parser = argparse.ArgumentParser( - description=" Convert VASP XDATCAR to extxyz format." -) -parser.add_argument("input", help=" Path to the input XDATCAR file") -parser.add_argument("output", help=" Path to the output .xyz file") +args = sys.argv[1:] +if len(args) < 2 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -xdat2exyz ") + print(" or: python xdatcar2exyz.py ") + print("") + print(" Arguments:") + print(" XDATCAR Path to the input XDATCAR file") + print(" output.xyz Path to the output extxyz file") + print("") + print(" Example: gpumdkit.sh -xdat2exyz XDATCAR output.xyz") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + +from ase.io import read, write -args = parser.parse_args() +input_file = sys.argv[1] +output_file = sys.argv[2] -# 2. Execute conversion logic +# Execute conversion logic try: - print(f" Reading XDATCAR: {args.input} ...") + print(f" Reading XDATCAR: {input_file} ...") # Read all frames from the trajectory (index=":") # ASE automatically parses scaling, lattice, and species - trajectory = read(args.input, index=":", format="vasp-xdatcar") + trajectory = read(input_file, index=":", format="vasp-xdatcar") num_frames = len(trajectory) print(f" Detected {num_frames} frames.") - print(f" Writing to extxyz: {args.output} ...") + print(f" Writing to extxyz: {output_file} ...") # Writing in extxyz format preserves the Lattice matrix in the header - write(args.output, trajectory, format="extxyz") + write(output_file, trajectory, format="extxyz") print(" Conversion complete.") except FileNotFoundError: - print(f" Error: Could not find '{args.input}'. Please check the path.") + print(f" Error: Could not find '{input_file}'. Please check the path.") sys.exit(1) except Exception as e: print(f" An unexpected error occurred: {e}") diff --git a/Scripts/plt_scripts/README.md b/Scripts/plt_scripts/README.md index 7d50d14..b217b1d 100644 --- a/Scripts/plt_scripts/README.md +++ b/Scripts/plt_scripts/README.md @@ -418,7 +418,7 @@ gpumdkit.sh -plt nemd [real_length] [scale_eff_size] [cutoff_freq] [save] **Params:** ``` -real_length : Real length of heat tranfer zone in nm (set to 'Auto', with auto-calculation) +real_length : Real length of heat transfer zone in nm (set to 'Auto', with auto-calculation) scale_eff_size: Optional, Scale factor for effective cross-sectional area (default: 1) • For 3D bulk systems: use 1 • For low-dimensional systems with vacuum layer: S_box / S_eff @@ -598,7 +598,7 @@ gpumdkit.sh -plt dimer Li Li nep.txt Dimer comparison -**Reference:** [arXiv:2504.15925](https://doi.org/10.48550/arXiv.2504.15925) +**Reference:** [J. Chem. Inf. Model. 2026, 66, 3, 1406-1413](https://doi.org/10.1021/acs.jcim.5c02335) --- @@ -683,7 +683,7 @@ For quick reference, here's the complete command list: ``` +-----------------------------------------------------------------------------------------------+ - | GPUMDkit 1.5.5 (dev) (2026-05-10) PLOT & VISUALIZATION TOOLS | + | GPUMDkit 1.5.6 (dev) (2026-06-17) PLOT & VISUALIZATION TOOLS | +-----------------------------------------------------------------------------------------------+ | Usage: gpumdkit.sh -plt Help: gpumdkit.sh -plt -h | +-----------------------------------------------------------------------------------------------+ diff --git a/Scripts/plt_scripts/plt_arrhenius_d.py b/Scripts/plt_scripts/plt_arrhenius_d.py index 88e84a1..da3e70a 100644 --- a/Scripts/plt_scripts/plt_arrhenius_d.py +++ b/Scripts/plt_scripts/plt_arrhenius_d.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_arrhenius_d.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_arrhenius_d_xyz.py b/Scripts/plt_scripts/plt_arrhenius_d_xyz.py index 0888897..c94b4ee 100644 --- a/Scripts/plt_scripts/plt_arrhenius_d_xyz.py +++ b/Scripts/plt_scripts/plt_arrhenius_d_xyz.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_arrhenius_d_xyz.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_arrhenius_sigma.py b/Scripts/plt_scripts/plt_arrhenius_sigma.py index 4102f80..6611d63 100644 --- a/Scripts/plt_scripts/plt_arrhenius_sigma.py +++ b/Scripts/plt_scripts/plt_arrhenius_sigma.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_arrhenius_sigma.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_arrhenius_sigma_xyz.py b/Scripts/plt_scripts/plt_arrhenius_sigma_xyz.py index 333b0fc..169a05e 100644 --- a/Scripts/plt_scripts/plt_arrhenius_sigma_xyz.py +++ b/Scripts/plt_scripts/plt_arrhenius_sigma_xyz.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_arrhenius_sigma_xyz.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_born_charge.py b/Scripts/plt_scripts/plt_born_charge.py index 8614abf..f7f1a2b 100644 --- a/Scripts/plt_scripts/plt_born_charge.py +++ b/Scripts/plt_scripts/plt_born_charge.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_born_charge.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_charge.py b/Scripts/plt_scripts/plt_charge.py index cf534aa..abe8179 100644 --- a/Scripts/plt_scripts/plt_charge.py +++ b/Scripts/plt_scripts/plt_charge.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_charge.py Category: Plot Scripts @@ -13,8 +13,11 @@ python plt_charge.py [save] Arguments: save Save the plot as 'charge.png' instead of displaying it +Input files (required in working directory): + train.xyz Training structures in extxyz format + charge_train.out Charge data from qNEP model Output: - Display of charge distribution plot + charge.png Charge distribution plot (saved or displayed) Author: Zihan YAN (yanzihan@westlake.edu.cn) Last-modified: 2026-05-16 ============================================================================= diff --git a/Scripts/plt_scripts/plt_cohesive.py b/Scripts/plt_scripts/plt_cohesive.py index d22fdd1..09ebd92 100644 --- a/Scripts/plt_scripts/plt_cohesive.py +++ b/Scripts/plt_scripts/plt_cohesive.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_cohesive.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_descriptors.py b/Scripts/plt_scripts/plt_descriptors.py index 2b22273..6441dcb 100644 --- a/Scripts/plt_scripts/plt_descriptors.py +++ b/Scripts/plt_scripts/plt_descriptors.py @@ -3,14 +3,14 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_descriptors.py Category: Plot Scripts Purpose: Visualize high-dimensional NEP descriptors using dimensionality reduction (PCA or UMAP) with configurable file paths and labels. -Usage: gpumdkit.sh -plt des - python plt_descriptors.py ... +Usage: gpumdkit.sh -plt des ... + python plt_descriptors.py ... Arguments: method Dimensionality reduction method: 'pca' or 'umap' file1... Paths to .npy files containing descriptors @@ -110,7 +110,8 @@ def plot_reduced_data(reduced_splits, labels, method): def main(): # Check command-line arguments if len(sys.argv) < 3: - print("Usage: python scripts.py ...") + print("Usage: gpumdkit.sh -plt des ...") + print(" or: python plt_descriptors.py ...") print("Method: 'pca' or 'umap'") sys.exit(1) @@ -131,4 +132,4 @@ def main(): plot_reduced_data(reduced_splits, labels, method) if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/Scripts/plt_scripts/plt_descriptors_compare.py b/Scripts/plt_scripts/plt_descriptors_compare.py index aa3133d..f44e6bc 100644 --- a/Scripts/plt_scripts/plt_descriptors_compare.py +++ b/Scripts/plt_scripts/plt_descriptors_compare.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_descriptors_compare.py Category: Plot Scripts @@ -30,6 +30,14 @@ import os import matplotlib.pyplot as plt + +def print_dependency_notice(): + print(" This function requires the calorine package.") + print(" If you use this function, we recommend citing:") + print(" Lindgren et al., J. Open Source Softw. 9, 6264 (2024).") + print(" https://doi.org/10.21105/joss.06264") + + plt.rcParams.update({ "font.family": "sans-serif", "font.sans-serif": ["Arial", "DejaVu Sans", "Liberation Sans"], @@ -46,7 +54,7 @@ def print_progress_bar(iteration, total, prefix='', suffix='', decimals=1, lengt # Check command-line arguments if len(sys.argv) < 5: - print(" Usage: python calc_descriptors.py method nep.txt element train1.xyz [train2.xyz ...]") + print(" Usage: python plt_descriptors_compare.py method nep.txt element train1.xyz [train2.xyz ...]") print(" method: 'pca' or 'umap'") print(" element: chemical symbol (e.g., Li) or 'total'") sys.exit(1) @@ -54,6 +62,8 @@ def print_progress_bar(iteration, total, prefix='', suffix='', decimals=1, lengt method, model_file, target_element = sys.argv[1:4] xyz_files = sys.argv[4:] +print_dependency_notice() + # Validate method if method.lower() not in ['pca', 'umap']: print(" Error: Method must be 'pca' or 'umap'.") @@ -120,7 +130,6 @@ def print_progress_bar(iteration, total, prefix='', suffix='', decimals=1, lengt # Save descriptors # output_file = f"{os.path.splitext(xyz_file)[0]}_descriptors.npy" # np.save(output_file, file_descriptors) - # print(f"Saved descriptors to '{output_file}' (shape: {file_descriptors.shape})") # Check if any descriptors were collected if not all_descriptors: @@ -173,4 +182,4 @@ def print_progress_bar(iteration, total, prefix='', suffix='', decimals=1, lengt print("The plot has been automatically saved as 'descriptors.png'.") plt.savefig('descriptors.png', dpi=300) else: - plt.show() \ No newline at end of file + plt.show() diff --git a/Scripts/plt_scripts/plt_dimer.py b/Scripts/plt_scripts/plt_dimer.py index f9541b1..b6fde58 100644 --- a/Scripts/plt_scripts/plt_dimer.py +++ b/Scripts/plt_scripts/plt_dimer.py @@ -3,14 +3,14 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_dimer.py Category: Plot Scripts Purpose: Plot dimer interaction curves (energy and force vs distance) for a pair of atoms using a NEP model. -Usage: gpumdkit.sh -plt dimer - python plt_dimer.py +Usage: gpumdkit.sh -plt dimer [save] + python plt_dimer.py [save] Arguments: element1, element2 Atom symbols (e.g., Li Li) nep_dir Path to the NEP potential file (e.g., ./nep.txt) @@ -27,6 +27,14 @@ from calorine.calculators import CPUNEP import sys + +def print_dependency_notice(): + print(" This function requires the calorine package.") + print(" If you use this function, we recommend citing:") + print(" Lindgren et al., J. Open Source Softw. 9, 6264 (2024).") + print(" https://doi.org/10.21105/joss.06264") + + plt.rcParams.update({ "font.family": "sans-serif", "font.sans-serif": ["Arial", "DejaVu Sans", "Liberation Sans"], @@ -34,7 +42,8 @@ # Check the number of command-line arguments if len(sys.argv) < 4: - print("Usage: python plt_dimer.py ") + print("Usage: gpumdkit.sh -plt dimer [save]") + print(" or: python plt_dimer.py ") print("Example: python plt_dimer.py Li Li ./nep.txt") sys.exit(1) @@ -43,6 +52,8 @@ symbol2 = sys.argv[2] # Type of the second atom nep_path = sys.argv[3] # Directory of the NEP potential file +print_dependency_notice() + # Set the range and step size for distances start_distance = 0.1 # Starting distance in Angstrom end_distance = 6.0 # Ending distance in Angstrom @@ -123,4 +134,4 @@ print(f"The plot has been automatically saved as 'dimer-{symbol1}-{symbol2}.png'.") plt.savefig(f'dimer-{symbol1}-{symbol2}.png', dpi=300) else: - plt.show() \ No newline at end of file + plt.show() diff --git a/Scripts/plt_scripts/plt_doas.py b/Scripts/plt_scripts/plt_doas.py index 9faceda..2fff1da 100644 --- a/Scripts/plt_scripts/plt_doas.py +++ b/Scripts/plt_scripts/plt_doas.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_doas.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_emd.py b/Scripts/plt_scripts/plt_emd.py index e6a9c22..585cff7 100644 --- a/Scripts/plt_scripts/plt_emd.py +++ b/Scripts/plt_scripts/plt_emd.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_emd.py Category: Plot Scripts @@ -79,7 +79,7 @@ def process(self): with open(self.path['run'], 'r') as file: for line in file: if 'time_step' in line: - time_step = int(line.split()[1]) + time_step = float(line.split()[1]) if 'compute_hac' in line: N_hac_data = int(int(line.split()[2]) / int(line.split()[3])) Max_cor_time = int(int(line.split()[1]) * int(line.split()[2])) @@ -87,7 +87,7 @@ def process(self): N_repeat = len(raw_data) // N_hac_data if len(raw_data) % N_hac_data != 0: raise ValueError(f"The MD calculation seems to be not completed, please check it!") - Time_upper = Max_cor_time * 1e-6 # ns + Time_upper = Max_cor_time * time_step * 1e-6 # ns # Classify and process data initially for col in raw_data.columns: diff --git a/Scripts/plt_scripts/plt_force_errors.py b/Scripts/plt_scripts/plt_force_errors.py index 49c2ec5..e051bba 100644 --- a/Scripts/plt_scripts/plt_force_errors.py +++ b/Scripts/plt_scripts/plt_force_errors.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_force_errors.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_hnemd.py b/Scripts/plt_scripts/plt_hnemd.py index 967a369..6c81b01 100644 --- a/Scripts/plt_scripts/plt_hnemd.py +++ b/Scripts/plt_scripts/plt_hnemd.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_hnemd.py Category: Plot Scripts @@ -47,7 +47,7 @@ def set_fig_properties(ax_list, tl=4, tw=1.2, tlm=4): def print_usage(): """Print usage instructions""" - print("Usage: gpumdkit -plt hnemd [scale_eff_size] [cutoff_freq] [save]") + print("Usage: gpumdkit.sh -plt hnemd [scale_eff_size] [cutoff_freq] [save]") print("Params:") print(" scale_eff_size: Optional, Scale factor for effective cross-sectional area (default: 1)") print(" • For 3D bulk systems: use 1") @@ -431,4 +431,4 @@ def _plot_results(self, Reformed_HNEMD_data, Reformed_SHC_data, res_h, res_s, processor = HNEMD_Processor(directory, scale_eff_size, cutoff_freq) processor.process() - # python plt_hnemd.py [scale_eff_size] [cutoff_freq] [save] \ No newline at end of file + # python plt_hnemd.py [scale_eff_size] [cutoff_freq] [save] diff --git a/Scripts/plt_scripts/plt_learning_rate.py b/Scripts/plt_scripts/plt_learning_rate.py index ed580c3..0b0a1f9 100644 --- a/Scripts/plt_scripts/plt_learning_rate.py +++ b/Scripts/plt_scripts/plt_learning_rate.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_learning_rate.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_msd.py b/Scripts/plt_scripts/plt_msd.py index 58f6a07..7524a7c 100644 --- a/Scripts/plt_scripts/plt_msd.py +++ b/Scripts/plt_scripts/plt_msd.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_msd.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_msd_all.py b/Scripts/plt_scripts/plt_msd_all.py index a1709d0..2fad542 100644 --- a/Scripts/plt_scripts/plt_msd_all.py +++ b/Scripts/plt_scripts/plt_msd_all.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_msd_all.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_msd_convergence_check.py b/Scripts/plt_scripts/plt_msd_convergence_check.py index d971bac..a32ac83 100644 --- a/Scripts/plt_scripts/plt_msd_convergence_check.py +++ b/Scripts/plt_scripts/plt_msd_convergence_check.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_msd_convergence_check.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_msd_sdc.py b/Scripts/plt_scripts/plt_msd_sdc.py index 05bcbd4..d6f6272 100644 --- a/Scripts/plt_scripts/plt_msd_sdc.py +++ b/Scripts/plt_scripts/plt_msd_sdc.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_msd_sdc.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_nemd.py b/Scripts/plt_scripts/plt_nemd.py index db5fb78..0ed0ae9 100644 --- a/Scripts/plt_scripts/plt_nemd.py +++ b/Scripts/plt_scripts/plt_nemd.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_nemd.py Category: Plot Scripts @@ -47,7 +47,7 @@ def set_fig_properties(ax_list, tl=4, tw=1.2, tlm=4): def print_usage(): """Print usage instructions""" - print("Usage: gpumdkit -plt nemd [real_length] [scale_eff_size] [cutoff_freq] [save]") + print("Usage: gpumdkit.sh -plt nemd [real_length] [scale_eff_size] [cutoff_freq] [save]") print("Params:") print(" real_length : Real length of heat tranfer zone in nm (set to 'Auto', with auto-calculation)") print(" scale_eff_size: Optional, Scale factor for effective cross-sectional area (default: 1)") @@ -57,7 +57,7 @@ def print_usage(): print(" - S_eff: real or effective area of the system") print(" cutoff_freq : Optional, Cutoff frequency for SHC calculation in THz (default: 60)") print(" save : Optional, save the plot as 'nemd.png'") - print(" !!! Note !!! : If no SHC data, set [scale_eff_size] and [cutoff_freq] to any number as placeholders when using 'save'.") + print(" !!! Note !!! : If no SHC data, set [scale_eff_size] and [cutoff_freq] to any non-zero number as placeholders when using 'save'.") class NEMD_Processor: def __init__(self, _directory, _real_length=None, _scale_eff_size=1, _cutoff_freq=60, _scale_vacuum=1): @@ -186,6 +186,7 @@ def process(self): Reformed_NEMD_data = {} # Get parameters from run.in + direction = None # heat transfer axis; set by compute_shc, else auto-detected below with open(self.path['run'], 'r') as file: found_nemd = False for line in file: @@ -232,6 +233,14 @@ def process(self): group = group_arr else: group = group_arr[:, 0] + + if direction is None: + # No compute_shc in run.in: infer the heat transfer axis as the + # Cartesian direction where the source/sink groups are most separated + heat_pos = model.positions[(group == 1)].mean(axis=0) + cold_pos = model.positions[(group == N_temp_group - 1)].mean(axis=0) + direction = int(np.argmax(np.abs(heat_pos - cold_pos))) + coords_heat = model.positions[(group == 1), direction].mean() coords_cold = model.positions[(group == N_temp_group - 1), direction].mean() xticks_length = np.linspace(coords_heat, coords_cold, N_temp_group - 1) * 0.1 @@ -278,7 +287,6 @@ def _print_nemd_results(self, Reformed_NEMD_data, Length): print("NEMD Thermal Conductivity Results") print("=" * 70) print(f"\nEffective length: {Length:.4f} nm") - # print(f"Scale_vacuum: {self.scale_vacuum}") print(f"Scale_eff_size: {self.scale_eff_size}\n") print(f"Thermal conductance G = {Reformed_NEMD_data['G'][0, -2]:.6f} ± {Reformed_NEMD_data['G'][0, -1]:.6f} MW/m²K") print(f"Thermal conductivity κ = {Reformed_NEMD_data['k'][0, -2]:.6f} ± {Reformed_NEMD_data['k'][0, -1]:.6f} W/mK") @@ -440,4 +448,4 @@ def _plot_results(self, Reformed_NEMD_data, Reformed_SHC_data, res_s, processor = NEMD_Processor(directory, real_length, scale_eff_size, cutoff_freq) processor.process() - # python plt_nemd.py [real_length] [scale_eff_size] [cutoff_freq] [save] \ No newline at end of file + # python plt_nemd.py [real_length] [scale_eff_size] [cutoff_freq] [save] diff --git a/Scripts/plt_scripts/plt_nep_restart.py b/Scripts/plt_scripts/plt_nep_restart.py index a389a2f..1940648 100644 --- a/Scripts/plt_scripts/plt_nep_restart.py +++ b/Scripts/plt_scripts/plt_nep_restart.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_nep_restart.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_net_force.py b/Scripts/plt_scripts/plt_net_force.py index a8a88ab..074ab7b 100644 --- a/Scripts/plt_scripts/plt_net_force.py +++ b/Scripts/plt_scripts/plt_net_force.py @@ -3,13 +3,13 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_net_force.py Category: Plot Scripts Purpose: Plot distribution of net forces on structures to identify problematic configurations in training datasets. -Usage: gpumdkit.sh -plt net_force +Usage: gpumdkit.sh -plt net_force [save] python plt_net_force.py [save] Arguments: extxyzfile Path to the extended XYZ file (e.g., train.xyz) @@ -39,7 +39,7 @@ def parse_xyz_file(xyz_file): # Read number of atoms try: num_atoms = int(lines[i].strip()) - except: + except (ValueError, IndexError): i += 1 continue @@ -217,7 +217,8 @@ def check_convergence(xyz_file, threshold=0.001, save_flag=False): # Main function def main(): if len(sys.argv) < 2: - print(" Usage: python plt_net_force.py train.xyz [save]") + print(" Usage: gpumdkit.sh -plt net_force [save]") + print(" or: python plt_net_force.py [save]") sys.exit(1) xyz_file = sys.argv[1] diff --git a/Scripts/plt_scripts/plt_parity_density.py b/Scripts/plt_scripts/plt_parity_density.py index d944554..3862e74 100644 --- a/Scripts/plt_scripts/plt_parity_density.py +++ b/Scripts/plt_scripts/plt_parity_density.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_parity_density.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_pdos.py b/Scripts/plt_scripts/plt_pdos.py index 3fa9a18..f1c28fa 100644 --- a/Scripts/plt_scripts/plt_pdos.py +++ b/Scripts/plt_scripts/plt_pdos.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_pdos.py Category: Plot Scripts @@ -45,7 +45,8 @@ def set_fig_properties(ax_list, tl=4, tw=1.2, tlm=4): trap = np.trapezoid if hasattr(np, "trapezoid") else np.trapz def print_usage(): - print("Usage: python plt_vac_dos.py [save]") + print("Usage: gpumdkit.sh -plt pdos [save]") + print(" or: python plt_pdos.py [save]") print(" save : Optional. If provided, saves figures (.png) and data (.xlsx).") class VAC_DOS_Processor: @@ -370,4 +371,4 @@ def _save_excel(self, nu, dx, dy, dz, T, cx, cy, cz): directory = os.getcwd() processor = VAC_DOS_Processor(directory) - processor.process(save_mode) \ No newline at end of file + processor.process(save_mode) diff --git a/Scripts/plt_scripts/plt_plane_grid.py b/Scripts/plt_scripts/plt_plane_grid.py index b7596ed..b782ca6 100644 --- a/Scripts/plt_scripts/plt_plane_grid.py +++ b/Scripts/plt_scripts/plt_plane_grid.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_plane_grid.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_prediction.py b/Scripts/plt_scripts/plt_prediction.py index ba36883..c5ea16f 100644 --- a/Scripts/plt_scripts/plt_prediction.py +++ b/Scripts/plt_scripts/plt_prediction.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_prediction.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_prediction2.py b/Scripts/plt_scripts/plt_prediction2.py index ad555a3..7fb5ec7 100644 --- a/Scripts/plt_scripts/plt_prediction2.py +++ b/Scripts/plt_scripts/plt_prediction2.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_prediction2.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_rdf.py b/Scripts/plt_scripts/plt_rdf.py index 133cc86..2f009dc 100644 --- a/Scripts/plt_scripts/plt_rdf.py +++ b/Scripts/plt_scripts/plt_rdf.py @@ -3,19 +3,18 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_rdf.py Category: Plot Scripts Purpose: Plot radial distribution function (RDF) from rdf.out showing pair correlations for all atom pairs. -Usage: gpumdkit.sh -plt rdf [column] [save] +Usage: gpumdkit.sh -plt rdf [save] python plt_rdf.py [save] Arguments: - column Optional column index to plot a specific RDF pair - save Save the plot as PNG instead of displaying it + save Save the plot as 'rdf.png' instead of displaying it Output: - RDF plot(s) displayed or saved + rdf.png RDF plot (saved or displayed) Author: Zihan YAN (yanzihan@westlake.edu.cn) Last-modified: 2026-05-16 ============================================================================= diff --git a/Scripts/plt_scripts/plt_rdf_pmf.py b/Scripts/plt_scripts/plt_rdf_pmf.py index 49a93fe..c522b9f 100644 --- a/Scripts/plt_scripts/plt_rdf_pmf.py +++ b/Scripts/plt_scripts/plt_rdf_pmf.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_rdf_pmf.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_sdc.py b/Scripts/plt_scripts/plt_sdc.py index 3d6c948..8c4b726 100644 --- a/Scripts/plt_scripts/plt_sdc.py +++ b/Scripts/plt_scripts/plt_sdc.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_sdc.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_thermo.py b/Scripts/plt_scripts/plt_thermo.py index a89ef10..1cfe764 100644 --- a/Scripts/plt_scripts/plt_thermo.py +++ b/Scripts/plt_scripts/plt_thermo.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_thermo.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_thermo2.py b/Scripts/plt_scripts/plt_thermo2.py index 9fa8818..07d3063 100644 --- a/Scripts/plt_scripts/plt_thermo2.py +++ b/Scripts/plt_scripts/plt_thermo2.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_thermo2.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_thermo3.py b/Scripts/plt_scripts/plt_thermo3.py index a13d9de..321dc80 100644 --- a/Scripts/plt_scripts/plt_thermo3.py +++ b/Scripts/plt_scripts/plt_thermo3.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_thermo3.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_train.py b/Scripts/plt_scripts/plt_train.py index 8a5f4eb..bed9b94 100644 --- a/Scripts/plt_scripts/plt_train.py +++ b/Scripts/plt_scripts/plt_train.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_train.py Category: Plot Scripts @@ -34,7 +34,7 @@ # plt.rcParams['axes.prop_cycle'] = cycler(color=custom_colors) # Load data -loss = np.loadtxt('loss.out') +loss = np.loadtxt('loss.out', comments='#') energy_data = np.loadtxt('energy_train.out') force_data = np.loadtxt('force_train.out') stress_data = np.loadtxt('stress_train.out') @@ -67,16 +67,24 @@ def calculate_limits(train_data, padding=0.08): # Create a subplot with 2 rows and 2 columns fig, axs = plt.subplots(2, 2, figsize=(9, 7), dpi=100) -if loss[0, 0] == 100: - xlabel = 'Generation/100' - plot_cols = slice(1, 7) # loss[:, 1:7] - legend_labels = ['Total', 'L1-Reg', 'L2-Reg', 'Energy-train', 'Force-train', 'Virial-train'] -elif loss[0, 0] == 1: +if loss.shape[1] == 6: # torchnep xlabel = 'Epoch' - plot_cols = slice(1, 5) # loss[:, 1:5] - legend_labels = ['Total', 'Energy-train', 'Force-train', 'Virial-train'] + plot_cols = slice(1, 5) + legend_labels = ['Loss', 'Energy-train', 'Force-train', 'Virial-train'] +elif loss.shape[1] >= 9: # nep/gnep + step = loss[1, 0] - loss[0, 0] + if step == 100: + xlabel = 'Generation/100' + plot_cols = slice(1, 7) + legend_labels = ['Total', 'L1-Reg', 'L2-Reg', 'Energy-train', 'Force-train', 'Virial-train'] + elif step == 1: + xlabel = 'Epoch' + plot_cols = slice(1, 5) + legend_labels = ['Total', 'Energy-train', 'Force-train', 'Virial-train'] + else: + raise ValueError(f"Unsupported step size: {step}") else: - raise ValueError("Unexpected loss data format.") + raise ValueError(f"Unsupported loss format with {loss.shape[1]} columns") # Plotting the loss figure axs[0, 0].loglog(loss[:, plot_cols], '-', linewidth=2) diff --git a/Scripts/plt_scripts/plt_train_density.py b/Scripts/plt_scripts/plt_train_density.py index 6b8baf4..97bbaae 100644 --- a/Scripts/plt_scripts/plt_train_density.py +++ b/Scripts/plt_scripts/plt_train_density.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_train_density.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_train_test.py b/Scripts/plt_scripts/plt_train_test.py index 06eb442..01a9b1f 100644 --- a/Scripts/plt_scripts/plt_train_test.py +++ b/Scripts/plt_scripts/plt_train_test.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_train_test.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_vac.py b/Scripts/plt_scripts/plt_vac.py index d5fe943..5af1fd4 100644 --- a/Scripts/plt_scripts/plt_vac.py +++ b/Scripts/plt_scripts/plt_vac.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_vac.py Category: Plot Scripts diff --git a/Scripts/plt_scripts/plt_viscosity.py b/Scripts/plt_scripts/plt_viscosity.py index a782bb0..957c22f 100644 --- a/Scripts/plt_scripts/plt_viscosity.py +++ b/Scripts/plt_scripts/plt_viscosity.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: plt_viscosity.py Category: Plot Scripts diff --git a/Scripts/sample_structures/README.md b/Scripts/sample_structures/README.md index 76130f6..6525345 100644 --- a/Scripts/sample_structures/README.md +++ b/Scripts/sample_structures/README.md @@ -25,21 +25,23 @@ Structure sampling is crucial for creating diverse configurations. These scripts | |_| | __/| |_| | | | | |_| | <| | |_ \____|_| \___/|_| |_|____/|_|\_\_|\__| - GPUMDkit Version 1.4.2 (dev) (2025-12-17) + GPUMDkit Version 1.5.6 (dev) (2026-06-17) Core Developer: Zihan YAN (yanzihan@westlake.edu.cn) + Main Contributors: Denan LI, Xin WU, Zhoulin LIU & Chen HUA ----------------------- GPUMD ----------------------- - 1) Format Conversion 2) Sample Structures - 3) Workflow 4) Calculators - 5) Analyzer 6) Developing ... - 0) Quit! + 1) Format Conversion 2) Sample Structures + 3) Workflow 4) Calculators + 5) Analyzer 6) Visualization + 7) Utilities 8) Help + 0) Exit ------------>> Input the function number: 2 ------------>> 201) Sample structures from extxyz - 202) Sample structures by pynep - 203) Sample structures by neptrain + 202) PyNEP sampling [deprecated] + 203) FPS sampling by NepTrain [preferred] 204) Perturb structure 205) Select max force deviation structs 000) Return to the main menu @@ -47,6 +49,155 @@ Structure sampling is crucial for creating diverse configurations. These scripts Input the function number: ``` +--- + +## Scripts + +### sample_structures.py + +This script samples frames from an extxyz trajectory using either uniform or random sampling. + +#### Usage + +```sh +python sample_structures.py [skip_initial] +``` + +- ``: `uniform` or `random` +- `[skip_initial]`: optional number of initial frames to skip; default is `0` + +#### Example + +```sh +python sample_structures.py train.xyz uniform 50 +``` + +#### Interactive Mode Example + +``` +201) Sample structures from extxyz +Input [skip_num] +[skip_num]: number of initial frames to skip, default value is 0 +Sampling_method: 'uniform' or 'random' +Example: train.xyz uniform 50 +``` + +The output file is `sampled_structures.xyz`. + + + +### pynep_select_structs.py / parallel_pynep_select_structs.py + +PyNEP-based FPS sampling is kept for compatibility, but it is only executed through `gpumdkit.sh -pynep`. The interactive `202` entry only prints a notice and does not run PyNEP. The interactive sampling menu uses `203) FPS sampling by NepTrain` for descriptor-based FPS. + +#### Direct Usage + +```sh +python pynep_select_structs.py +python parallel_pynep_select_structs.py +``` + +#### GPUMDkit Entry + +```sh +gpumdkit.sh -pynep +``` + +Then input: + +```sh +dump.xyz train.xyz nep.txt 8 +``` + + + +### neptrain_select_structs.py + +This script selects diverse structures from candidate structures using NepTrain descriptors and farthest-point sampling. + +#### Usage + +```sh +python neptrain_select_structs.py +``` + +#### Example + +```sh +python neptrain_select_structs.py dump.xyz train.xyz nep.txt +``` + +#### Interactive Mode Example + +``` +203) FPS sampling by NepTrain [preferred] +Input +Example: dump.xyz train.xyz nep.txt +``` + +This function requires the `NepTrain` package. If you use this function, we recommend citing the NepTrain paper. + + + +### perturb_structure.py + +This script generates perturbed structures from an input VASP structure. + +#### Usage + +```sh +python perturb_structure.py +``` + +#### Example + +```sh +python perturb_structure.py POSCAR 20 0.03 0.2 uniform +``` + +#### Interactive Mode Example + +``` +204) Perturb structure +Input +The default parameters for perturb are 20 0.03 0.2 uniform +Example: POSCAR 20 0.03 0.2 uniform +``` + +This function requires the `dpdata` package. If you use this function, we recommend citing dpdata. + + + +### select_max_modev.py + +This script selects structures with large maximum force deviation from GPUMD active-learning output files. + +#### Required Files + +- `active.out` +- `active.xyz` + +#### Usage + +```sh +python select_max_modev.py +``` + +#### Example + +```sh +python select_max_modev.py 200 0.15 +``` + +#### Interactive Mode Example + +``` +205) Select max force deviation structs +Input (eg. 200 0.15) +``` + +The output file is `selected.xyz`. + ## Contributing See [CONTRIBUTING.md](../../CONTRIBUTING.md) for detailed guidelines. diff --git a/Scripts/sample_structures/frame_range.py b/Scripts/sample_structures/frame_range.py index b59d4fd..d0fab35 100644 --- a/Scripts/sample_structures/frame_range.py +++ b/Scripts/sample_structures/frame_range.py @@ -3,13 +3,14 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: frame_range.py Category: Sample Structure Scripts Purpose: Extract a range of frames from an extxyz trajectory by start and end fractions (e.g., first 80% or last 50%). -Usage: python frame_range.py +Usage: gpumdkit.sh -frame_range + python frame_range.py Arguments: input.xyz Input extxyz trajectory file start_fraction Start fraction (0.0 to 1.0, e.g., 0 for beginning) @@ -22,14 +23,25 @@ """ import sys -from ase.io import read, write -# Check command line arguments -if len(sys.argv) != 4: - print(" Usage: python frame_range.py input.xyz start_fraction end_fraction") - print(" Example: python frame_range.py dump.xyz 0 0.8") - print(" Example: python frame_range.py dump.xyz 0.5 1") - sys.exit(1) +args = sys.argv[1:] +if len(args) < 3 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -frame_range ") + print(" or: python frame_range.py ") + print("") + print(" Arguments:") + print(" exyzfile Input extxyz trajectory file") + print(" start_fraction Start fraction (0.0 to 1.0, e.g., 0 for beginning)") + print(" end_fraction End fraction (0.0 to 1.0, e.g., 0.8 for first 80%)") + print("") + print(" Output:") + print(" __.xyz Extracted frame range") + print("") + print(" Example: gpumdkit.sh -frame_range dump.xyz 0.2 0.5") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + +from ase.io import read, write input_file = sys.argv[1] start_fraction = float(sys.argv[2]) diff --git a/Scripts/sample_structures/neptrain_select_structs.py b/Scripts/sample_structures/neptrain_select_structs.py index b500029..4ced0c9 100644 --- a/Scripts/sample_structures/neptrain_select_structs.py +++ b/Scripts/sample_structures/neptrain_select_structs.py @@ -3,14 +3,16 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: neptrain_select_structs.py Category: Sample Structure Scripts Purpose: Select diverse structures from a sampledata set using farthest-point sampling on NepTrain descriptors, relative to an existing training set. -Usage: python neptrain_select_structs.py +Usage: gpumdkit.sh + choose 203) FPS sampling by NepTrain + python neptrain_select_structs.py Arguments: sampledata_file Extxyz file with candidate structures traindata_file Extxyz file with existing training structures @@ -25,12 +27,33 @@ """ import sys -import numpy as np -from ase.io import read, write -import matplotlib.pyplot as plt -from sklearn.decomposition import PCA -from NepTrain.core.nep import * -from scipy.spatial.distance import cdist + + +def print_dependency_notice(): + print(" This function requires the NepTrain package.") + print(" If you use this function, we recommend citing:") + print(" Chen et al., Comput. Phys. Commun. 317, 109859 (2025).") + print(" https://doi.org/10.1016/j.cpc.2025.109859") + + +def print_usage(): + print(" Usage: gpumdkit.sh") + print(" choose 203) FPS sampling by NepTrain") + print(" or: python neptrain_select_structs.py ") + print("") + print(" Arguments:") + print(" sampledata_file Extxyz file with candidate structures") + print(" traindata_file Extxyz file with existing training structures") + print(" nep_model_file NEP model file (e.g., nep.txt)") + print("") + print(" Output:") + print(" selected.xyz") + print(" select.png") + print(" pca_sample.txt, pca_train.txt, pca_selected.txt") + print("") + print(" Example: in interactive mode, enter: dump.xyz train.xyz nep.txt") + print(" python neptrain_select_structs.py dump.xyz train.xyz nep.txt") + print("") def print_progress_bar(iteration, total, prefix='', suffix='', decimals=1, length=50, fill='█'): @@ -87,10 +110,23 @@ def FarthestPointSample(new_data, now_data=[], min_distance=None, min_select=1, return to_add -# Check command line arguments -if len(sys.argv) < 4: - print(" Usage: python pynep_select_structs.py ") - print(" Examp: python pynep_select_structs.py dump.xyz train.xyz nep.txt") +args = sys.argv[1:] +if len(args) != 3 or args[0] in ("-h", "--help"): + print_usage() + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + +print_dependency_notice() + +try: + import numpy as np + from ase.io import read, write + import matplotlib.pyplot as plt + from sklearn.decomposition import PCA + from NepTrain.core.nep import Nep3Calculator + from scipy.spatial.distance import cdist +except ImportError: + print(" Error: required Python dependencies are not installed or cannot be imported.") + print(" Please install NepTrain and the scientific Python stack before using this function.") sys.exit(1) # Load data diff --git a/Scripts/sample_structures/parallel_pynep_select_structs.py b/Scripts/sample_structures/parallel_pynep_select_structs.py index 66ef14c..6f27af3 100644 --- a/Scripts/sample_structures/parallel_pynep_select_structs.py +++ b/Scripts/sample_structures/parallel_pynep_select_structs.py @@ -3,19 +3,20 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: parallel_pynep_select_structs.py Category: Sample Structure Scripts Purpose: Parallelized version of pynep_select_structs.py. Select diverse structures using farthest-point sampling on pynep descriptors with multi-processing for descriptor computation and I/O. -Usage: python parallel_pynep_select_structs.py [threads] +Usage: gpumdkit.sh -pynep + python parallel_pynep_select_structs.py Arguments: sampledata_file Extxyz file with candidate structures traindata_file Extxyz file with existing training structures nep_model_file NEP model file (e.g., nep.txt) - threads (optional) Number of parallel workers + threads Number of parallel workers Output: selected.xyz Selected diverse structures select.png PCA visualization of descriptor space @@ -25,18 +26,36 @@ """ import sys -import numpy as np -from ase.io import read, write -import matplotlib.pyplot as plt -from sklearn.decomposition import PCA -from pynep.calculate import NEP -from pynep.select import FarthestPointSample from concurrent.futures import ProcessPoolExecutor, as_completed import multiprocessing import argparse -import time import os + +def print_dependency_notice(): + print(" This function requires the pynep package.") + print(" This PyNEP sampling entry is deprecated. We recommend using NepTrain sampling instead.") + + +def print_usage(): + print(" Usage: gpumdkit.sh -pynep") + print(" or: python parallel_pynep_select_structs.py ") + print("") + print(" Arguments:") + print(" sampledata_file Extxyz file with candidate structures") + print(" traindata_file Extxyz file with existing training structures") + print(" nep_model_file NEP model file (e.g., nep.txt)") + print(" threads Number of parallel workers") + print("") + print(" Output:") + print(" selected.xyz Selected diverse structures") + print(" select.png PCA visualization of descriptor space") + print("") + print(" Example: gpumdkit.sh -pynep") + print(" dump.xyz train.xyz nep.txt 8") + print("") + + def get_num_frames(file_path): count = 0 with open(file_path, 'r') as f: @@ -118,11 +137,10 @@ def calculate_descriptors(data, desc_type, max_workers=None): return np.array(results) -# Check command line arguments -if len(sys.argv) < 4: - print(" Usage: python pynep_select_structs.py ") - print(" Examp: python pynep_select_structs.py dump.xyz train.xyz nep.txt") - sys.exit(1) +args_in = sys.argv[1:] +if len(args_in) != 4 or args_in[0] in ("-h", "--help"): + print_usage() + sys.exit(0 if args_in and args_in[0] in ("-h", "--help") else 1) # Parse command-line arguments parser = argparse.ArgumentParser(description='Select structures using NEP descriptors.') @@ -132,6 +150,20 @@ def calculate_descriptors(data, desc_type, max_workers=None): parser.add_argument('threads', type=int, default=multiprocessing.cpu_count(), help='Number of threads for parallel processing') args = parser.parse_args() +print_dependency_notice() + +try: + import numpy as np + from ase.io import read, write + import matplotlib.pyplot as plt + from sklearn.decomposition import PCA + from pynep.calculate import NEP + from pynep.select import FarthestPointSample +except ImportError: + print(" Error: required Python dependencies are not installed or cannot be imported.") + print(" Please install pynep and the scientific Python stack, or use function 203) NepTrain sampling instead.") + sys.exit(1) + # Function to load data from file def load_data(file_path): return read(file_path, ':') diff --git a/Scripts/sample_structures/perturb_structure.py b/Scripts/sample_structures/perturb_structure.py index 012c2bb..69a0252 100644 --- a/Scripts/sample_structures/perturb_structure.py +++ b/Scripts/sample_structures/perturb_structure.py @@ -3,14 +3,16 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: perturb_structure.py Category: Sample Structure Scripts Purpose: Generate perturbed structures from a POSCAR/CONTCAR file using dpdata. Supports cell and atom perturbations with different perturbation styles (normal, uniform, const). -Usage: python perturb_structure.py +Usage: gpumdkit.sh + choose 204) Perturb structure + python perturb_structure.py Arguments: input.vasp Input POSCAR/CONTCAR file pert_num Number of perturbed structures to generate @@ -26,11 +28,47 @@ import argparse import sys -import dpdata + + +def print_dependency_notice(): + print(" This function requires the dpdata package.") + print(" If you use this function, we recommend citing dpdata according to its official documentation.") + + +def print_usage(): + print(" Usage: gpumdkit.sh") + print(" choose 204) Perturb structure") + print(" or: python perturb_structure.py ") + print("") + print(" Arguments:") + print(" input.vasp Input POSCAR/CONTCAR file") + print(" pert_num Number of perturbed structures to generate") + print(" cell_pert_fraction Fraction of cell perturbation") + print(" atom_pert_distance Distance of atom perturbation (Angstrom)") + print(" atom_pert_style Style: normal, uniform, or const") + print("") + print(" Output:") + print(" POSCAR_*.vasp") + print("") + print(" Example: in interactive mode, enter: POSCAR 20 0.03 0.2 uniform") + print(" python perturb_structure.py POSCAR 20 0.03 0.2 uniform") + print("") + def parse_args(): parser = argparse.ArgumentParser( - description="Usage: python script.py ") + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""Generate perturbed structures from a POSCAR/CONTCAR file. + +Usage: + gpumdkit.sh + choose 204) Perturb structure + python perturb_structure.py + +Example: + in interactive mode, enter: POSCAR 20 0.03 0.2 uniform + python perturb_structure.py POSCAR 20 0.03 0.2 uniform +""") parser.add_argument('input_file', help='The path to POSCAR/CONTCAR file') parser.add_argument('pert_num', type=int, default=20, help='The perturbation number') parser.add_argument('cell_pert_fraction', type=float, default=0.03, help='The fraction of cell perturbation') @@ -39,12 +77,28 @@ def parse_args(): return parser.parse_args() def main(): + args_in = sys.argv[1:] + if len(args_in) != 5 and not (args_in and args_in[0] in ("-h", "--help")): + print_usage() + sys.exit(1) + try: args = parse_args() - except SystemExit: + except SystemExit as exc: + if exc.code == 0: + sys.exit(0) print(f"Default values: pert_num=20, cell_pert_fraction=0.03, atom_pert_distance=0.2, atom_pert_style=uniform") print("atom_pert_style options: 'normal', 'uniform', 'const'") print("dpdata documentation: https://docs.deepmodeling.com/projects/dpdata/en/master/index.html \n") + sys.exit(exc.code) + + print_dependency_notice() + + try: + import dpdata + except ImportError: + print(" Error: dpdata is not installed or cannot be imported.") + print(" Please install dpdata before using this function.") sys.exit(1) # Read the POSCAR file and perform perturbation diff --git a/Scripts/sample_structures/pynep_select_structs.py b/Scripts/sample_structures/pynep_select_structs.py index 51e87a8..9da9456 100644 --- a/Scripts/sample_structures/pynep_select_structs.py +++ b/Scripts/sample_structures/pynep_select_structs.py @@ -3,7 +3,7 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: pynep_select_structs.py Category: Sample Structure Scripts @@ -31,6 +31,12 @@ from pynep.calculate import NEP from pynep.select import FarthestPointSample + +def print_dependency_notice(): + print(" This function requires the pynep package.") + print(" This PyNEP sampling entry is deprecated. We recommend using NepTrain sampling instead.") + + def print_progress_bar(iteration, total, prefix='', suffix='', decimals=1, length=50, fill='█'): percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) filled_length = int(length * iteration // total) @@ -66,9 +72,11 @@ def calculate_descriptors(): # Check command line arguments if len(sys.argv) < 4: print(" Usage: python pynep_select_structs.py ") - print(" Examp: python pynep_select_structs.py dump.xyz train.xyz nep.txt") + print(" Example: python pynep_select_structs.py dump.xyz train.xyz nep.txt") sys.exit(1) +print_dependency_notice() + # Load data sampledata = read(sys.argv[1], ':') traindata = read(sys.argv[2], ':') @@ -153,4 +161,4 @@ def calculate_descriptors(): plt.tight_layout() #plt.show() -plt.savefig('select.png') \ No newline at end of file +plt.savefig('select.png') diff --git a/Scripts/sample_structures/sample_structures.py b/Scripts/sample_structures/sample_structures.py index 7ec9d80..0b9c08c 100644 --- a/Scripts/sample_structures/sample_structures.py +++ b/Scripts/sample_structures/sample_structures.py @@ -3,13 +3,15 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: sample_structures.py Category: Sample Structure Scripts Purpose: Uniformly or randomly sample a specified number of frames from an extxyz trajectory, with an option to skip initial frames. -Usage: python sample_structures.py [skip_initial] +Usage: gpumdkit.sh + choose 201) Sample structures from extxyz + python sample_structures.py [skip_initial] Arguments: extxyz_file Input extxyz trajectory file method Sampling method: uniform or random @@ -46,7 +48,13 @@ def parse_args(): Modified by: Dr. Huan Wang Usage: - python sample_structures.py [skip_initial]) + gpumdkit.sh + choose 201) Sample structures from extxyz + python sample_structures.py [skip_initial] + + Example: + in interactive mode, enter: dump.xyz uniform 50 + python sample_structures.py dump.xyz random 100 500 """)) parser.add_argument('extxyz_file', type=Path, @@ -112,4 +120,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/Scripts/sample_structures/select_max_modev.py b/Scripts/sample_structures/select_max_modev.py index 91930d7..2fcac5e 100644 --- a/Scripts/sample_structures/select_max_modev.py +++ b/Scripts/sample_structures/select_max_modev.py @@ -3,13 +3,15 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: select_max_modev.py Category: Sample Structure Scripts Purpose: Extract the top N structures with the highest max force deviation from active learning output (active.out + active.xyz). -Usage: python select_max_modev.py +Usage: gpumdkit.sh + choose 205) Select max force deviation structs + python select_max_modev.py Arguments: top_n Number of top structures to extract min_deviation Minimum force deviation threshold for filtering @@ -27,15 +29,48 @@ import numpy as np from ase.io import read, write + +def print_usage(): + print(" Usage: gpumdkit.sh") + print(" choose 205) Select max force deviation structs") + print(" or: python select_max_modev.py ") + print("") + print(" Arguments:") + print(" top_n Number of top structures to extract") + print(" min_deviation Minimum force deviation threshold for filtering") + print("") + print(" Input files:") + print(" active.out Max force deviation per structure") + print(" active.xyz Corresponding structures in extxyz format") + print("") + print(" Output:") + print(" selected.xyz") + print("") + print(" Example: in interactive mode, enter: 200 0.15") + print(" python select_max_modev.py 200 0.15") + print("") + + +args = sys.argv[1:] +if len(args) != 2 or args[0] in ("-h", "--help"): + print_usage() + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + +try: + top_n = int(args[0]) + min_deviation = float(args[1]) +except ValueError: + print(" Error: must be an integer and must be a number.") + print("") + print_usage() + sys.exit(1) + # Define file paths input_file = 'active.out' # Input file for max force deviation #output_file = 'filtered_max_force_deviations.txt' # Output file for filtered max force deviations xyz_file = 'active.xyz' # Input .extxyz file output_xyz_file = 'selected.xyz' # Output file for extracted structures -# Number of top structures to extract -top_n = int(sys.argv[1]) # Specify the number of top structures to extract (e.g., top 100) - # Lists to store filtered max force deviations and corresponding indices filtered_deviations = [] filtered_indices = [] @@ -48,7 +83,7 @@ time, max_force_deviation = line.split() max_force_deviation = float(max_force_deviation) - if max_force_deviation > float(sys.argv[2]): + if max_force_deviation > min_deviation: filtered_deviations.append(max_force_deviation) filtered_indices.append(idx) # Store the index in the original file @@ -73,7 +108,7 @@ def extract_xyz_structures(xyz_file, indices, output_xyz_file): atoms_list = read(xyz_file, index=':') # Read all structures as a list of ASE atoms objects # Extract the corresponding structures based on the indices from the filtered list - selected_atoms = [atoms_list[i] for i in indices] + selected_atoms = [atoms_list[filtered_indices[i]] for i in indices] # Write the selected structures to the output .xyz file write(output_xyz_file, selected_atoms) @@ -82,4 +117,3 @@ def extract_xyz_structures(xyz_file, indices, output_xyz_file): # Extract the top N structures and save them to the output .xyz file extract_xyz_structures(xyz_file, top_indices_in_filtered, output_xyz_file) - diff --git a/Scripts/utils/README.md b/Scripts/utils/README.md new file mode 100644 index 0000000..2b920e7 --- /dev/null +++ b/Scripts/utils/README.md @@ -0,0 +1,73 @@ +
+

🛠️ Utility Scripts

+

Utility scripts provide maintenance helpers for GPUMDkit itself and small data-cleanup tools used by command-line workflows.

+
+ +## Overview + +| Tool | Entry | Purpose | +|------|-------|---------| +| `clean_extra_files.sh` | `gpumdkit.sh -clean` | Interactively remove temporary files in the current directory | +| `update_gpumdkit.sh` | `gpumdkit.sh -update` or `gpumdkit.sh -U` | Pull the latest GPUMDkit code from the current Git branch | +| `completion.sh` | sourced by the installer | Bash completion for `gpumdkit.sh` commands | +| `renumber_atoms.py` | `gpumdkit.sh -re_atoms ` | Renumber atom IDs in LAMMPS dump files | +| `nep_modifier/` | `gpumdkit.sh -nep_modifier` | Interactive NEP model editing utilities | + +--- + +## Clean Extra Files + +```bash +gpumdkit.sh -clean +``` + +This helper scans the current directory and proposes files to remove. It keeps common GPUMDkit input files such as `run.in`, `nep.in`, `model.xyz`, `nep.txt`, `train.xyz`, and `test.xyz`, plus shell/slurm submission files. + +Before deleting anything, it prints the candidate file list and asks for confirmation: + +```text +Do you want to delete all these files? +y/yes to delete, n/no to cancel, or input files to keep (separated by spaces): +``` + +Use this command only after checking that the current directory is the calculation folder you intend to clean. + +--- + +## Update GPUMDkit + +```bash +gpumdkit.sh -update +gpumdkit.sh -U +``` + +The updater checks the current Git branch against the remote GPUMDkit repository and runs `git pull` when updates are available. If the command is launched outside a Git repository, it tries to use the configured `GPUMDkit_path`. + +--- + +## Shell Completion + +`completion.sh` provides Bash completion for common GPUMDkit options, plot types, and calculator types. It is normally configured by the installer, so users do not need to run it manually. + +--- + +## Renumber LAMMPS Atom IDs + +```bash +gpumdkit.sh -re_atoms dump.lammpstrj renumbered.lammpstrj +``` + +This command rewrites atom IDs in each `ITEM: ATOMS` section of a LAMMPS dump file so that IDs start from 1 in every frame. + +--- + +## NEP Modifier + +```bash +gpumdkit.sh -nep_modifier +``` + +The NEP modifier is an interactive utility for editing NEP model files. See: + +- `Scripts/utils/nep_modifier/README.md` +- `Scripts/utils/nep_modifier/README_zh-CN.md` diff --git a/Scripts/utils/clean_extra_files.sh b/Scripts/utils/clean_extra_files.sh index d59a220..c030602 100644 --- a/Scripts/utils/clean_extra_files.sh +++ b/Scripts/utils/clean_extra_files.sh @@ -5,10 +5,15 @@ function clean_extra_files(){ keep_files=("run.in" "nep.in" "model.xyz" "nep.txt" "train.xyz" "test.xyz") keep_patterns=("*sub*" "*.sh" "*slurm") -all_files=$(ls) delete_files=() -for file in $all_files; do +# Build the deletion list using a glob (avoids parsing `ls` output), +# considering only regular files (matches the net effect of plain `ls`, +# where subdirectory names would have failed `rm -f` anyway). +for file in *; do + [ -e "$file" ] || continue + [ -f "$file" ] || continue + # Check if the file matches any keep_files or keep_patterns keep=false for keep_file in "${keep_files[@]}"; do @@ -32,50 +37,68 @@ done # Display files to delete if [ ${#delete_files[@]} -eq 0 ]; then - echo "No files to delete." - exit 0 + echo " No files to delete." + return 0 else - echo "The following files will be deleted:" - echo "---------------------------------------" + echo " The following files will be deleted:" + echo " ----------------------------------------------------" for file in "${delete_files[@]}"; do - echo -n "$file " + echo " ${file}" done - echo -e "\n---------------------------------------" + echo " ----------------------------------------------------" fi # Ask user for confirmation or additional files to keep -echo "Do you want to delete all these files?" -echo "y/yes to delete, n/no to cancel, or input files to keep (separated by spaces):" -read user_input +echo " +------------------------------------------------------+" +echo " | Do you want to delete all these files? |" +echo " | y / yes : delete all |" +echo " | n / no : cancel |" +echo " | or input filenames to keep (space-separated) |" +echo " +------------------------------------------------------+" +if ! IFS= read -r -p " " user_input; then + echo " Input closed. No files were deleted." + return 1 +fi # Process user input if [[ "$user_input" == "y" || "$user_input" == "yes" ]]; then - echo "Deleting the files..." + echo " Deleting the files..." for file in "${delete_files[@]}"; do rm -f "$file" done - echo "Files deleted." + echo " Files deleted." elif [[ "$user_input" == "n" || "$user_input" == "no" ]]; then - echo "Operation canceled. No files were deleted." - exit 0 + echo " Operation canceled. No files were deleted." + return 0 else - # Add extra files to keep based on user input - extra_keep_files=($user_input) - for extra_file in "${extra_keep_files[@]}"; do - delete_files=("${delete_files[@]/$extra_file}") + # Add extra files to keep based on user input. + # Tokenize and exclude by whole-word match (NOT substring removal, + # which would corrupt names sharing a substring with the keep input). + read -r -a extra_keep_files <<< "$user_input" + new_delete_files=() + for df in "${delete_files[@]}"; do + skip=false + for ek in "${extra_keep_files[@]}"; do + if [ "$df" = "$ek" ]; then + skip=true + break + fi + done + if [ "$skip" = false ]; then + new_delete_files+=("$df") + fi done + delete_files=("${new_delete_files[@]}") # Delete remaining files if [ ${#delete_files[@]} -eq 0 ]; then - echo "No files to delete after processing extra keep files." + echo " No files to delete after processing extra keep files." else - echo "Deleting remaining files..." + echo " Deleting remaining files..." for file in "${delete_files[@]}"; do - if [ -n "$file" ]; then - rm -f "$file" - fi + rm -f "$file" done - echo "Files deleted." + echo " Files deleted." fi fi } \ No newline at end of file diff --git a/Scripts/utils/completion.sh b/Scripts/utils/completion.sh index b1f8ff5..63bf70d 100644 --- a/Scripts/utils/completion.sh +++ b/Scripts/utils/completion.sh @@ -13,7 +13,16 @@ _gpumdkit_completions() { prev="${COMP_WORDS[COMP_CWORD-1]}" # Previous word # List of primary options (extracted from gpumdkit.sh) - local opts="-h -update -help -clean -time -plt -calc -cbc -range -out2xyz -xml2xyz -pos2exyz -cif2pos -cif2exyz -exyz2pos -pos2lmp -lmp2exyz -traj2exyz -cp2k2xyz -addgroup -addlabel -addweight -min_dist -min_dist_pbc -filter_dist -filter_dist_pbc -filter_box -filter_value -get_frame -clean_xyz -get_volume -analyze_comp -replicate -hbond -pda -pynep -frame_range -chem_species -xdat2exyz" + local opts="-h -help -update -U -clean -time -plt -calc -cbc -range -out2xyz -out2exyz -cp2k2xyz -pos2exyz -cif2pos -cif2exyz -exyz2pos -xdat2exyz -pos2lmp -lmp2exyz -traj2exyz -dp2xyz -addgroup -addlabel -addweight -min_dist -min_dist_pbc -filter_dist -filter_dist_pbc -filter_box -filter_value -filter_range -get_frame -clean_xyz -analyze_comp -chem_species -replicate -pda -pynep -frame_range -nep_modifier" + + # Calculator subcommands + local calc_subcmds="ionic-cond nep des doas neb minimize msd nlist disp avg-struct oct-tilt pol-abo3" + + # If we are completing a subcommand right after -calc + if [[ "$prev" == "-calc" ]]; then + COMPREPLY=($(compgen -W "$calc_subcmds" -- "$cur")) + return + fi # Provide secondary completion based on the previous word case "$prev" in @@ -23,14 +32,10 @@ _gpumdkit_completions() { # Secondary options for -plt -plt) - COMPREPLY=($(compgen -W "thermo thermo2 thermo3 train train_density prediction test train_test msd msd_all msd_conv sdc rdf vac restart dimer force_error des doas charge lr parity_density arrhenius_d arrhenius_sigma sigma D sigma_xyz D_xyz net_force emd nemd hnemd pdos plane-grid cohesive viscosity rdf_pmf bec born_charge" -- "$cur")) ;; + COMPREPLY=($(compgen -W "thermo thermo2 thermo3 train train_density prediction test train_test parity_density born_charge bec msd msd_all msd_conv msd_sdc sdc rdf rdf_pmf vac restart dimer force_errors des doas charge lr arrhenius_d arrhenius_sigma sigma D sigma_xyz D_xyz net_force emd nemd hnemd pdos plane-grid cohesive viscosity" -- "$cur")) ;; - # Secondary options for -calc - -calc) - COMPREPLY=($(compgen -W "ionic-cond nep des doas neb nlist disp avg-struct oct-tilt pol-abo3" -- "$cur")) ;; - # Options requiring files or directories, complete with filenames - -out2xyz|-cp2k2xyz|-exyz2pos|-min_dist|-min_dist_pbc|-filter_dist|-filter_dist_pbc|-filter_box|-get_frame|-clean_xyz|-mtp2xyz|-pos2exyz|-cif2exyz|-cif2pos|-pos2lmp|-lmp2exyz|-traj2exyz|-addgroup|-addlabel|-addweight|-analyze_comp|-replicate|-pda|-cbc|-frame_range|-xml2xyz|-chem_species|-xdat2exyz) + -out2xyz|-out2exyz|-cp2k2xyz|-exyz2pos|-min_dist|-min_dist_pbc|-filter_dist|-filter_dist_pbc|-filter_box|-filter_value|-filter_range|-get_frame|-clean_xyz|-pos2exyz|-cif2exyz|-cif2pos|-pos2lmp|-lmp2exyz|-traj2exyz|-dp2xyz|-addgroup|-addlabel|-addweight|-analyze_comp|-replicate|-pda|-cbc|-frame_range|-chem_species|-xdat2exyz) COMPREPLY=($(compgen -f -- "$cur")) ;; # Default case: complete primary options @@ -39,5 +44,7 @@ _gpumdkit_completions() { esac } -# Register the completion function +# Register the completion function for gpumdkit.sh and common invocations complete -F _gpumdkit_completions gpumdkit.sh +complete -F _gpumdkit_completions ./gpumdkit.sh +complete -F _gpumdkit_completions gpumdkit diff --git a/Scripts/utils/nep_modifier/README.md b/Scripts/utils/nep_modifier/README.md new file mode 100644 index 0000000..b31c7de --- /dev/null +++ b/Scripts/utils/nep_modifier/README.md @@ -0,0 +1,298 @@ +# NEP Model Modifier + +> **English** | [简体中文](./README_zh-CN.md) + +> **WARNING**: This feature is currently in **testing**. The documentation was generated by AI and may contain errors. If you encounter any issues, please report them or join the QQ group: [825696376](https://qun.qq.com/universal-share/share?ac=1&authKey=buBNi1ADDzIFF2oZ1yA5FywG3LA9EL9yKZmb%2BN2MMz7nNuuxTas54wH7BgPEqP0s&busi_data=eyJncm91cENvZGUiOiI4MjU2OTYzNzYiLCJ0b2tlbiI6IlRxL1RLTDlOK3U2ekRSUXJ1TkNTUWd3ODNVV3BrdG9HN2lWWmJKMHAraGlDNzBZWFFyRUY2dUlSaW8rbUd4MisiLCJ1aW4iOiIxNDg5NjQ3MTc5In0%3D&data=fa4zSsT_IdI4ftCT_wwpytYHf--TaTB35lH0Jac5JHVpYoyXw3_3bZ1l1NZejsOZnGJku5u3BCbf5_bgrCkhZg&svctype=4&tempid=h5_group_info). + +An interactive CLI tool for modifying NEP (neuroevolution potential) models, powered by the [calorine](https://gitlab.com/materials-modeling/calorine) Python package (Lindgren et al., [JOSS, 2024, 9(95), 6264](https://doi.org/10.21105/joss.06264)). + +A trained NEP model can serve as the starting point for further development rather than as a final product. Common workflows include: + +- **Increasing capacity**: expand the number of neurons or add higher-body descriptor terms when the initial architecture turns out to be too small. +- **Adding a charge output**: promote a plain potential model to a charge-aware qNEP model by attaching a charge output head, then continue training with charge targets. +- **Species manipulation**: prune a multi-element model down to a subset of elements, or extend an existing model with a new species without discarding the learned potential surface. +- **Reducing capacity**: remove neurons or descriptor terms that contribute little to accuracy, for faster inference or as a starting point for fine-tuning on a narrower dataset. + +## Features + +| Operation | Description | Retraining Required? | +|-----------|-------------|---------------------| +| `augment()` | Expand neurons, descriptors, or add a charge head | Yes | +| `prune()` | Reduce neurons, remove descriptor terms, or drop the charge head | Yes | +| `remove_species()` | Remove one or more species | No (optional) | +| `keep_species()` | Retain a subset of species, dropping all others | No (optional) | +| `add_species()` | Add one or more species | Yes | + +All operations return a new Model instance; the source model is never modified in place. + +## Dependencies + +This tool requires the `calorine` Python package (>= 3.4). + +```bash +# Option 1: Install from PyPI +pip install 'calorine>=3.4' + +# Option 2: Install the latest version from GitLab +pip install git+https://gitlab.com/materials-modeling/calorine.git@master +``` + +## Input Files + +| File | Description | Required | +|------|-------------|----------| +| `nep.txt` | NEP model file | Yes | +| `nep.restart` | SNES restart file (stores optimizer state for fine-tuning) | No | + +The restart file stores a mean `mu` and a standard deviation `sigma` for every parameter; these are the current estimate of the SNES optimizer of the optimal value and exploration width, respectively. Loading the restart file is required for `augment`, `prune`, and `add_species` operations to properly initialize new and existing parameters. + +## Usage + +#### Interactive Mode + +1. Open your terminal and navigate to the directory containing your NEP model files. + +2. Run the tool: + + ``` + python nep_modifier.py + ``` + +3. At startup, the tool displays a header with citation information, then prompts for input files. Press **Enter** to use defaults (`nep.txt nep.restart` in the current directory): + + ``` + +----------------------------------------------------+ + | NEP Model Modifier (calorine) | + +----------------------------------------------------+ + | Powered by calorine package. If you use this tool,| + | please cite the following papers: | + | | + | Calorine: A Python package for constructing and | + | sampling neuroevolution potential models. | + | Journal of Open Source Software, 2024, 9, 6264. | + | https://doi.org/10.21105/joss.06264 | + +----------------------------------------------------+ + [!] WARNING: This feature is currently in TESTING. + [!] The tutorial/docs were generated by AI and may contain errors. + [!] Report issues or join the QQ group: 825696376 + +----------------------------------------------------+ + + Input (Enter to use defaults): + ------------>> + ``` + +4. After loading, the tool displays model information and a menu: + + ``` + ----------------------------------------------------- + Version : 4 + Model type : potential + Types : ('H', 'Li', 'B', 'N', 'O', ...) + Radial cutoff : 6.0 + Angular cutoff : 5.0 + n_max (rad/ang) : 6 / 6 + basis_size : 6 / 6 + l_max (3b/4b/5b) : 4 / 2 / 1 + n_neuron : 50 + n_parameters : 218858 + ----------------------------------------------------- + + Choose an operation: + 1) augment (expand neurons/descriptors/charge) + 2) prune (shrink neurons/descriptors) + 3) add_species (add element) + 4) remove_species (remove element) + 5) keep_species (keep selected elements only) + 6) Show model info + 7) Export model + 0) Exit + ------------>> + ``` + +#### Command-Line Mode + +You can also launch the tool directly from `gpumdkit.sh`: + +``` +gpumdkit.sh -nep_modifier +``` + +## Operations + +### 1) augment - Expand Model + +`augment()` applies one or more structural changes atomically and returns a new model. Options: + +- **Increase n_neuron**: Add more neurons to the hidden layer. The existing trained weights are preserved; new neurons are initialized with `mu=0` and `sigma=sigma_new`. +- **Increase l_max_5b**: Enable 5-body descriptor terms. This adds `n_max_angular + 1` new descriptor dimensions. +- **Add charge_head**: Promote a plain NEP model (`potential`) to a charge-aware qNEP model (`potential_with_charges`). A second output node is added per species. + +After augmentation, remember to update your `nep.in` file to match the new architecture before resuming training. + +### 2) prune - Shrink Model + +`prune()` returns a new model with a smaller architecture. Options: + +- **Reduce n_neuron**: Neurons are ranked by importance score and the least important ones are removed. +- **Reduce l_max_4b**: Remove 4-body descriptor terms (set to 0 to remove entirely). + +Surviving parameters receive adaptive SNES sigma values, re-opening the search distribution for the next training run. + +### 3) add_species - Add Elements + +Extends the model with: +- A new per-species ANN sub-network (for each added element) +- All new `(species_1, species_2)` descriptor weight pairs involving the new elements + +New parameters are initialized with `mu` drawn uniformly from [-1, 1] and `sigma = sigma_new`. The model must be trained further before the new element is meaningful. + +### 4) remove_species - Remove Elements + +Prunes all parameters associated with the listed elements: the ANN sub-networks, descriptor weight pairs, and their SNES statistics. A common use case is extracting a single-element model from a multi-element potential. + +### 5) keep_species - Keep Elements Only + +When isolating a small subset from a large foundation model, listing every species to drop via `remove_species()` is impractical. `keep_species()` accepts the elements to retain and derives the removal list automatically. + +## Examples + +#### Example 1: Extract a Sub-Model + +Extract Li, La, Zr, O from a 36-element foundation model: + +``` + Input (Enter to use defaults): + ------------>> + + Choose an operation: + 5) keep_species (keep selected elements only) + ------------>> + 5 + + Input elements to keep (space-separated): (Li La Zr O) + ------------>> + Li La Zr O + + Will keep: ['Li', 'La', 'Zr', 'O'] + Confirm? (y/n) + ------------>> + y + + Done: ('H', 'Li', ..., 'W') -> ('Li', 'O', 'Zr', 'La') + Params: 218858 -> 11818 + + Choose an operation: + 7) Export model + ------------>> + 7 + + Output directory: (.) + ------------>> + . + + Written: nep_modified.txt + Written: nep_modified.restart +``` + +#### Example 2: Expand Model Capacity + +Increase neurons from 50 to 80 and enable 5-body descriptors: + +``` + Choose an operation: + 1) augment (expand neurons/descriptors/charge) + ------------>> + 1 + + Choose what to augment: + 1) Increase n_neuron + 2) Increase l_max_5b + 3) Add charge_head + 0) Cancel + ------------>> + 1 + + Input new n_neuron: (60) + ------------>> + 80 + + Confirm augment? (y/n) + ------------>> + y + + Done: 218858 -> 345258 parameters +``` + +#### Example 3: Swap Elements + +Remove Pb and add Bi (chain operations): + +``` + Choose an operation: + 4) remove_species (remove element) + ------------>> + 4 + + Input elements to remove (space-separated): + ------------>> + Pb + + Confirm? (y/n) + ------------>> + y + + Done: ('Te', 'Pb') -> ('Te',) + Params: 2311 -> 1081 + + Choose an operation: + 3) add_species (add element) + ------------>> + 3 + + Input elements to add (space-separated): (Bi Sn) + ------------>> + Bi + + Confirm? (y/n) + ------------>> + y + + Done: ('Te',) -> ('Te', 'Bi') + Params: 1081 -> 2491 +``` + +## Output Files + +| File | Description | +|------|-------------| +| `nep_modified.txt` | Modified NEP model file | +| `nep_modified.restart` | Updated SNES restart file (if restart was loaded) | +| `nep_modified.in` | Training input file with updated architecture | + +Output files are named with a `_modified` suffix to avoid overwriting the originals. If a file with that name already exists, a numeric suffix (`_1`, `_2`, ...) is added automatically. + +To continue training with the modified model, place `nep_modified.txt` and `nep_modified.restart` in your GPUMD working directory and update `nep.in` accordingly. + +## Notes + +- All operations return a **new** Model instance; the source model is never modified in place. +- Loading the restart file is essential for proper parameter initialization during `augment`, `prune`, and `add_species`. +- When `augment()` adds new parameters, existing parameters retain their trained values (`mu` copied verbatim); `sigma` is re-opened to allow adaptation. +- After `prune()`, surviving parameters receive adaptive sigma: `max(sigma_floor, sigma_factor * |mu|)`. +- The `training_parameters` property returns architecture fields compatible with `write_nepfile()` for updating `nep.in`. + +## Citation + +If you use this tool in your research, please cite both calorine and GPUMDkit: + +**calorine:** + +> Lindgren, E., Rahm, M., Fransson, E., Eriksson, F., Österbacka, N., Fan, Z., & Erhart, P. calorine: A Python package for constructing and sampling neuroevolution potential models. [Journal of Open Source Software, 2024, 9, 6264](https://doi.org/10.21105/joss.06264). + +**GPUMDkit:** + +> Z. Yan\*, D. Li, X. Wu, Z. Liu, C. Hua, B. Situ, H. Yang, S. Tang, B. Tang, Z. Wang, S. Yi, H. Wang, D. Huang, K. Li, Q. Guo, Z. Chen, K. Xu, Y. Wang, Z. Wang, G. Tang, S. Liu, Z. Fan, and Y. Zhu\*. **GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP**. [MGE Advances, 2026, 4, e70074](https://doi.org/10.1002/mgea.70074). + +## Join Us + +Welcome to join our QQ group ([825696376](https://qun.qq.com/universal-share/share?ac=1&authKey=buBNi1ADDzIFF2oZ1yA5FywG3LA9EL9yKZmb%2BN2MMz7nNuuxTas54wH7BgPEqP0s&busi_data=eyJncm91cENvZGUiOiI4MjU2OTYzNzYiLCJ0b2tlbiI6IlRxL1RLTDlOK3U2ekRSUXJ1TkNTUWd3ODNVV3BrdG9HN2lWWmJKMHAraGlDNzBZWFFyRUY2dUlSaW8rbUd4MisiLCJ1aW4iOiIxNDg5NjQ3MTc5In0%3D&data=fa4zSsT_IdI4ftCT_wwpytYHf--TaTB35lH0Jac5JHVpYoyXw3_3bZ1l1NZejsOZnGJku5u3BCbf5_bgrCkhZg&svctype=4&tempid=h5_group_info)). Report issues or suggest features via [issues](https://github.com/zhyan0603/GPUMDkit/issues). diff --git a/Scripts/utils/nep_modifier/README_zh-CN.md b/Scripts/utils/nep_modifier/README_zh-CN.md new file mode 100644 index 0000000..68af01c --- /dev/null +++ b/Scripts/utils/nep_modifier/README_zh-CN.md @@ -0,0 +1,298 @@ +# NEP Model Modifier + +[English](./README.md) | **简体中文** + +> **注意**:此功能目前处于**测试阶段**。本文档由 AI 生成,可能存在错误。如有问题,请提交 [issue](https://github.com/zhyan0603/GPUMDkit/issues) 或加入 QQ 群:[825696376](https://qun.qq.com/universal-share/share?ac=1&authKey=buBNi1ADDzIFF2oZ1yA5FywG3LA9EL9yKZmb%2BN2MMz7nNuuxTas54wH7BgPEqP0s&busi_data=eyJncm91cENvZGUiOiI4MjU2OTYzNzYiLCJ0b2tlbiI6IlRxL1RLTDlOK3U2ekRSUXJ1TkNTUWd3ODNVV3BrdG9HN2lWWmJKMHAraGlDNzBZWFFyRUY2dUlSaW8rbUd4MisiLCJ1aW4iOiIxNDg5NjQ3MTc5In0%3D&data=fa4zSsT_IdI4ftCT_wwpytYHf--TaTB35lH0Jac5JHVpYoyXw3_3bZ1l1NZejsOZnGJku5u3BCbf5_bgrCkhZg&svctype=4&tempid=h5_group_info)。 + +基于 [calorine](https://gitlab.com/materials-modeling/calorine) Python 包(Lindgren et al., [JOSS, 2024, 9(95), 6264](https://doi.org/10.21105/joss.06264))的 NEP(神经演化势)模型交互式修改工具。 + +已训练的 NEP 模型可以作为进一步开发的起点,而非最终产品。常见的使用场景包括: + +- **扩展容量**:当初始架构过小时,增加神经元数量或添加更高体阶的描述符项。 +- **添加电荷输出**:将普通势函数模型升级为带电荷感知的 qNEP 模型,附加电荷输出头后继续训练。 +- **元素操作**:将多元素模型裁剪为元素子集,或在不丢弃已学习势函数面的情况下扩展新元素。 +- **缩减容量**:移除对精度贡献较小的神经元或描述符项,以加速推理或作为在更窄数据集上微调的起点。 + +## 功能特点 + +| 操作 | 说明 | 是否需要重新训练 | +|------|------|-----------------| +| `augment()` | 扩展神经元、描述符,或添加电荷头 | 是 | +| `prune()` | 减少神经元、移除描述符项,或删除电荷头 | 是 | +| `remove_species()` | 移除一个或多个元素 | 否(可选) | +| `keep_species()` | 保留元素子集,移除其他所有元素 | 否(可选) | +| `add_species()` | 添加一个或多个元素 | 是 | + +所有操作返回新的 Model 实例,源模型不会被原地修改。 + +## 依赖项 + +本工具需要 `calorine` Python 包(>= 3.4)。 + +```bash +# 方式一:从 PyPI 安装 +pip install 'calorine>=3.4' + +# 方式二:从 GitLab 安装最新版本 +pip install git+https://gitlab.com/materials-modeling/calorine.git@master +``` + +## 输入文件 + +| 文件 | 说明 | 是否必需 | +|------|------|---------| +| `nep.txt` | NEP 模型文件 | 是 | +| `nep.restart` | SNES 重启文件(存储优化器状态,用于微调) | 否 | + +restart 文件为每个参数存储均值 `mu` 和标准差 `sigma`,分别代表 SNES 优化器对最优值的当前估计和探索宽度。加载 restart 文件对于 `augment`、`prune` 和 `add_species` 操作正确初始化新旧参数至关重要。 + +## 使用方法 + +#### 交互模式 + +1. 打开终端,进入存放 NEP 模型文件的目录。 + +2. 运行工具: + + ``` + python nep_modifier.py + ``` + +3. 启动时工具会显示引用信息,然后提示输入文件。直接按 **Enter** 使用默认值(当前目录下的 `nep.txt nep.restart`): + + ``` + +----------------------------------------------------+ + | NEP Model Modifier (calorine) | + +----------------------------------------------------+ + | Powered by calorine package. If you use this tool,| + | please cite the following papers: | + | | + | Calorine: A Python package for constructing and | + | sampling neuroevolution potential models. | + | Journal of Open Source Software, 2024, 9, 6264. | + | https://doi.org/10.21105/joss.06264 | + +----------------------------------------------------+ + [!] WARNING: This feature is currently in TESTING. + [!] The tutorial/docs were generated by AI and may contain errors. + [!] Report issues or join the QQ group: 825696376 + +----------------------------------------------------+ + + Input (Enter to use defaults): + ------------>> + ``` + +4. 加载后,工具显示模型信息和操作菜单: + + ``` + ----------------------------------------------------- + Version : 4 + Model type : potential + Types : ('H', 'Li', 'B', 'N', 'O', ...) + Radial cutoff : 6.0 + Angular cutoff : 5.0 + n_max (rad/ang) : 6 / 6 + basis_size : 6 / 6 + l_max (3b/4b/5b) : 4 / 2 / 1 + n_neuron : 50 + n_parameters : 218858 + ----------------------------------------------------- + + Choose an operation: + 1) augment (expand neurons/descriptors/charge) + 2) prune (shrink neurons/descriptors) + 3) add_species (add element) + 4) remove_species (remove element) + 5) keep_species (keep selected elements only) + 6) Show model info + 7) Export model + 0) Exit + ------------>> + ``` + +#### 命令行模式 + +也可通过 `gpumdkit.sh` 直接启动: + +``` +gpumdkit.sh -nep_modifier +``` + +## 操作说明 + +### 1) augment - 扩展模型 + +`augment()` 原子性地应用一项或多项结构变更,返回新模型。可选项: + +- **Increase n_neuron**:增加隐藏层神经元。已训练的权重保留,新神经元以 `mu=0`、`sigma=sigma_new` 初始化。 +- **Increase l_max_5b**:启用 5-body 描述符项。新增 `n_max_angular + 1` 个描述符维度。 +- **Add charge_head**:将普通 NEP 模型(`potential`)升级为带电荷感知的 qNEP 模型(`potential_with_charges`),每个元素增加第二个输出节点。 + +扩展后,记得更新 `nep.in` 文件以匹配新架构,然后才能继续训练。 + +### 2) prune - 裁剪模型 + +`prune()` 返回架构更小的新模型。可选项: + +- **Reduce n_neuron**:按重要性得分对神经元排序,移除最不重要的神经元。 +- **Reduce l_max_4b**:移除 4-body 描述符项(设为 0 则完全移除)。 + +存活的参数会收到自适应的 SNES sigma 值,重新开启搜索分布以进行下一轮训练。 + +### 3) add_species - 添加元素 + +扩展模型: +- 为每个新元素添加新的 ANN 子网络 +- 添加所有涉及新元素的 `(species_1, species_2)` 描述符权重对 + +新参数以 `mu` 从 [-1, 1] 均匀采样、`sigma = sigma_new` 初始化。模型需要进一步训练才能使新元素有意义。 + +### 4) remove_species - 移除元素 + +移除与指定元素相关的所有参数:ANN 子网络、描述符权重对及其 SNES 统计量。常见用途是从多元素势函数中提取单元素模型。 + +### 5) keep_species - 仅保留指定元素 + +当从大型基础模型中隔离小子集时,通过 `remove_species()` 列出所有要移除的元素并不实际。`keep_species()` 接受要保留的元素,自动推导移除列表。 + +## 操作示例 + +#### 示例 1:提取子模型 + +从 36 元素基础模型中提取 Li、La、Zr、O: + +``` + Input (Enter to use defaults): + ------------>> + + Choose an operation: + 5) keep_species (keep selected elements only) + ------------>> + 5 + + Input elements to keep (space-separated): (Li La Zr O) + ------------>> + Li La Zr O + + Will keep: ['Li', 'La', 'Zr', 'O'] + Confirm? (y/n) + ------------>> + y + + Done: ('H', 'Li', ..., 'W') -> ('Li', 'O', 'Zr', 'La') + Params: 218858 -> 11818 + + Choose an operation: + 7) Export model + ------------>> + 7 + + Output directory: (.) + ------------>> + . + + Written: nep_modified.txt + Written: nep_modified.restart +``` + +#### 示例 2:扩展模型容量 + +将神经元从 50 增加到 80,并启用 5-body 描述符: + +``` + Choose an operation: + 1) augment (expand neurons/descriptors/charge) + ------------>> + 1 + + Choose what to augment: + 1) Increase n_neuron + 2) Increase l_max_5b + 3) Add charge_head + 0) Cancel + ------------>> + 1 + + Input new n_neuron: (60) + ------------>> + 80 + + Confirm augment? (y/n) + ------------>> + y + + Done: 218858 -> 345258 parameters +``` + +#### 示例 3:替换元素 + +移除 Pb 并添加 Bi(链式操作): + +``` + Choose an operation: + 4) remove_species (remove element) + ------------>> + 4 + + Input elements to remove (space-separated): + ------------>> + Pb + + Confirm? (y/n) + ------------>> + y + + Done: ('Te', 'Pb') -> ('Te',) + Params: 2311 -> 1081 + + Choose an operation: + 3) add_species (add element) + ------------>> + 3 + + Input elements to add (space-separated): (Bi Sn) + ------------>> + Bi + + Confirm? (y/n) + ------------>> + y + + Done: ('Te',) -> ('Te', 'Bi') + Params: 1081 -> 2491 +``` + +## 输出文件 + +| 文件 | 说明 | +|------|------| +| `nep_modified.txt` | 修改后的 NEP 模型文件 | +| `nep_modified.restart` | 更新后的 SNES 重启文件(仅在加载了 restart 时生成) | +| `nep_modified.in` | 包含更新架构的训练输入文件 | + +输出文件名自动添加 `_modified` 后缀,避免覆盖原始文件。如果同名文件已存在,则自动添加数字后缀(`_1`、`_2`……)。 + +如需使用修改后的模型继续训练,请将 `nep_modified.txt` 和 `nep_modified.restart` 放入 GPUMD 工作目录,并相应更新 `nep.in`。 + +## 注意事项 + +- 所有操作返回**新的** Model 实例,源模型不会被原地修改。 +- 加载 restart 文件对于 `augment`、`prune` 和 `add_species` 操作的正确参数初始化至关重要。 +- `augment()` 添加新参数时,现有参数保留其训练值(`mu` 原样复制);`sigma` 重新开启以允许自适应。 +- `prune()` 后,存活的参数收到自适应 sigma:`max(sigma_floor, sigma_factor * |mu|)`。 +- `training_parameters` 属性返回与 `write_nepfile()` 兼容的架构字段,可用于更新 `nep.in`。 + +## 引用 + +如果您在研究中使用了本工具,请同时引用 calorine 和 GPUMDkit: + +**calorine:** + +> Lindgren, E., Rahm, M., Fransson, E., Eriksson, F., Österbacka, N., Fan, Z., & Erhart, P. calorine: A Python package for constructing and sampling neuroevolution potential models. [Journal of Open Source Software, 2024, 9, 6264](https://doi.org/10.21105/joss.06264). + +**GPUMDkit:** + +> Z. Yan\*, D. Li, X. Wu, Z. Liu, C. Hua, B. Situ, H. Yang, S. Tang, B. Tang, Z. Wang, S. Yi, H. Wang, D. Huang, K. Li, Q. Guo, Z. Chen, K. Xu, Y. Wang, Z. Wang, G. Tang, S. Liu, Z. Fan, and Y. Zhu\*. **GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP**. [MGE Advances, 2026, 4, e70074](https://doi.org/10.1002/mgea.70074). + +## 加入我们 + +欢迎加入 QQ 群([825696376](https://qun.qq.com/universal-share/share?ac=1&authKey=buBNi1ADDzIFF2oZ1yA5FywG3LA9EL9yKZmb%2BN2MMz7nNuuxTas54wH7BgPEqP0s&busi_data=eyJncm91cENvZGUiOiI4MjU2OTYzNzYiLCJ0b2tlbiI6IlRxL1RLTDlOK3U2ekRSUXJ1TkNTUWd3ODNVV3BrdG9HN2lWWmJKMHAraGlDNzBZWFFyRUY2dUlSaW8rbUd4MisiLCJ1aW4iOiIxNDg5NjQ3MTc5In0%3D&data=fa4zSsT_IdI4ftCT_wwpytYHf--TaTB35lH0Jac5JHVpYoyXw3_3bZ1l1NZejsOZnGJku5u3BCbf5_bgrCkhZg&svctype=4&tempid=h5_group_info))。如有问题或建议,请提交 [issue](https://github.com/zhyan0603/GPUMDkit/issues)。 diff --git a/Scripts/utils/nep_modifier/nep_modifier.py b/Scripts/utils/nep_modifier/nep_modifier.py new file mode 100644 index 0000000..a4a15b7 --- /dev/null +++ b/Scripts/utils/nep_modifier/nep_modifier.py @@ -0,0 +1,345 @@ +""" +============================================================================= +GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP +Repository: https://github.com/zhyan0603/GPUMDkit +Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) +============================================================================= +Script: nep_modifier.py +Category: Model Modification Scripts +Purpose: Interactively modify NEP models using calorine. +Usage: python nep_modifier.py + +Author: Zihan YAN (yanzihan@westlake.edu.cn) +Last-modified: 2026-06-17 +============================================================================= +""" + +import os +import sys +from pathlib import Path + +try: + from calorine.nep import read_model, read_nepfile, write_nepfile +except ImportError: + print(" Error: calorine package (>=3.4) is required.") + print(" Install via pip:") + print(" pip install 'calorine>=3.4'") + print(" Or install the latest version from GitLab:") + print(" pip install git+https://gitlab.com/materials-modeling/calorine.git@master") + sys.exit(1) + + +def print_dependency_notice(): + print(" This function requires the calorine package.") + print(" If you use this function, we recommend citing:") + print(" Lindgren et al., J. Open Source Softw. 9, 6264 (2024).") + print(" https://doi.org/10.21105/joss.06264") + + +# ─── helpers ────────────────────────────────────────────────────────────────── + +def banner(title): + print(f" +---------------------------------------------------+") + print(f" | {title:<51}|") + print(f" +---------------------------------------------------+") + + +def separator(): + print(" -----------------------------------------------------") + + +def ask(prompt, hint=None): + if hint: + print(f" {prompt} ({hint})") + else: + print(f" {prompt}") + print(" ------------>>") + return input(" ").strip() + + +def confirm(msg): + print(f" {msg} (y/n)") + print(" ------------>>") + return input(" ").strip().lower() in ("y", "yes") + + +def safe_output_path(out_dir, base_name, ext): + path = out_dir / f"{base_name}{ext}" + if not path.exists(): + return path + i = 1 + while True: + path = out_dir / f"{base_name}_{i}{ext}" + if not path.exists(): + return path + i += 1 + + +# ─── core functions ─────────────────────────────────────────────────────────── + +def show_model_info(model): + separator() + print(f" Version : {model.version}") + print(f" Model type : {model.model_type}") + print(f" Types : {model.types}") + print(f" Radial cutoff : {model.radial_cutoff}") + print(f" Angular cutoff : {model.angular_cutoff}") + print(f" n_max (rad/ang) : {model.n_max_radial} / {model.n_max_angular}") + print(f" basis_size : {model.n_basis_radial} / {model.n_basis_angular}") + print(f" l_max (3b/4b/5b) : {model.l_max_3b} / {model.l_max_4b} / {model.l_max_5b}") + print(f" n_neuron : {model.n_neuron}") + print(f" n_parameters : {model.n_parameters}") + separator() + + +def op_augment(model): + banner("augment: Expand Model") + print(f" Current: neuron={model.n_neuron}, l_max_5b={model.l_max_5b}") + separator() + print(" Choose what to augment:") + print(" 1) Increase n_neuron") + print(" 2) Increase l_max_5b") + print(" 3) Add charge_head") + print(" 0) Cancel") + print(" ------------>>") + choice = input(" ").strip() + + kwargs = {} + if choice == "1": + val = ask(" Input new n_neuron:", str(model.n_neuron + 10)) + kwargs["n_neuron"] = int(val) + elif choice == "2": + val = ask(" Input new l_max_5b:", "1") + kwargs["l_max_5b"] = int(val) + elif choice == "3": + kwargs["charge_head"] = True + else: + print(" Cancelled.") + return model + + separator() + for k, v in kwargs.items(): + print(f" {k} = {v}") + + if not confirm(" Confirm augment?"): + return model + + new_model = model.augment(**kwargs) + print(f" Done: {model.n_parameters} -> {new_model.n_parameters} parameters") + return new_model + + +def op_prune(model): + banner("prune: Shrink Model") + print(f" Current: neuron={model.n_neuron}, l_max_4b={model.l_max_4b}") + separator() + print(" Choose what to prune:") + print(" 1) Reduce n_neuron") + print(" 2) Reduce l_max_4b") + print(" 0) Cancel") + print(" ------------>>") + choice = input(" ").strip() + + kwargs = {} + if choice == "1": + val = ask(" Input new n_neuron:", str(max(1, model.n_neuron - 10))) + kwargs["n_neuron"] = int(val) + elif choice == "2": + val = ask(" Input new l_max_4b (0 to remove):", "0") + kwargs["l_max_4b"] = int(val) + else: + print(" Cancelled.") + return model + + separator() + for k, v in kwargs.items(): + print(f" {k} = {v}") + + if not confirm(" Confirm prune?"): + return model + + new_model = model.prune(**kwargs) + print(f" Done: {model.n_parameters} -> {new_model.n_parameters} parameters") + return new_model + + +def op_add_species(model): + banner("add_species: Add Elements") + print(f" Current types: {model.types}") + val = ask(" Input elements to add (space-separated):", "Bi Sn") + species = val.split() + if not species: + print(" Cancelled.") + return model + + separator() + print(f" Will add: {species}") + if not confirm(" Confirm?"): + return model + + new_model = model.add_species(species) + print(f" Done: {model.types} -> {new_model.types}") + print(f" Params: {model.n_parameters} -> {new_model.n_parameters}") + return new_model + + +def op_remove_species(model): + banner("remove_species: Remove Elements") + print(f" Current types: {model.types}") + val = ask(" Input elements to remove (space-separated):") + species = val.split() + if not species: + print(" Cancelled.") + return model + + separator() + print(f" Will remove: {species}") + if not confirm(" Confirm?"): + return model + + new_model = model.remove_species(species) + print(f" Done: {model.types} -> {new_model.types}") + print(f" Params: {model.n_parameters} -> {new_model.n_parameters}") + return new_model + + +def op_keep_species(model): + banner("keep_species: Keep Elements Only") + print(f" Current types: {model.types}") + val = ask(" Input elements to keep (space-separated):", "Li La Zr O") + species = val.split() + if not species: + print(" Cancelled.") + return model + + separator() + print(f" Will keep: {species}") + if not confirm(" Confirm?"): + return model + + new_model = model.keep_species(species) + print(f" Done: {model.types} -> {new_model.types}") + print(f" Params: {model.n_parameters} -> {new_model.n_parameters}") + return new_model + + +def op_export(model, original_path): + banner("Export Model Files") + out_dir = ask(" Output directory:", ".") + out_dir = Path(out_dir) + out_dir.mkdir(parents=True, exist_ok=True) + + base = Path(original_path).stem + nep_out = safe_output_path(out_dir, base + "_modified", ".txt") + restart_out = out_dir / (nep_out.stem + ".restart") + + model.write(str(nep_out)) + print(f" Written: {nep_out}") + + try: + model.write_restart(str(restart_out)) + print(f" Written: {restart_out}") + except Exception: + print(" Skipped: nep.restart (no restart data loaded)") + + try: + if hasattr(model, "training_parameters"): + nep_in = out_dir / (nep_out.stem + ".in") + params = model.training_parameters + if Path("nep.in").exists(): + old = read_nepfile("nep.in") + old.update(params) + params = old + write_nepfile(params, str(out_dir)) + default_in = out_dir / "nep.in" + if default_in.exists() and default_in != nep_in: + default_in.rename(nep_in) + print(f" Written: {nep_in}") + except Exception: + pass + + separator() + + +# ─── main ───────────────────────────────────────────────────────────────────── + +def main(): + print("") + print(" +----------------------------------------------------+") + print(" | NEP Model Modifier (calorine) |") + print(" +----------------------------------------------------+") + print(" | Powered by calorine package. If you use this tool,|") + print(" | please cite the following papers: |") + print(" | |") + print(" | Calorine: A Python package for constructing and |") + print(" | sampling neuroevolution potential models. |") + print(" | Journal of Open Source Software, 2024, 9, 6264. |") + print(" | https://doi.org/10.21105/joss.06264 |") + print(" +----------------------------------------------------+") + print(" [!] WARNING: This feature is currently in TESTING.") + print(" [!] The docs were generated by AI and may contain errors.") + print(" [!] Report issues or join the QQ group: 825696376") + print(" +----------------------------------------------------+") + print("") + + val = ask(" Input (Enter to use defaults):") + parts = val.split() + nep_path = parts[0] if parts else "nep.txt" + restart_path = parts[1] if len(parts) > 1 else "nep.restart" + + if not Path(nep_path).exists(): + print(f" Error: file not found: {nep_path}") + return + if not Path(restart_path).exists(): + print(f" Warning: {restart_path} not found, skipping restart.") + restart_path = None + + separator() + print(" Loading model...") + if restart_path: + model = read_model(nep_path, restart_file=restart_path) + else: + model = read_model(nep_path) + print(" Model loaded successfully!") + + show_model_info(model) + + while True: + print("") + print(" Choose an operation:") + print(" 1) augment (expand neurons/descriptors/charge)") + print(" 2) prune (shrink neurons/descriptors)") + print(" 3) add_species (add element)") + print(" 4) remove_species (remove element)") + print(" 5) keep_species (keep selected elements only)") + print(" 6) Show model info") + print(" 7) Export model") + print(" 0) Exit") + print(" ------------>>") + choice = input(" ").strip() + + if choice == "0": + print(" Bye!") + break + elif choice == "1": + model = op_augment(model) + elif choice == "2": + model = op_prune(model) + elif choice == "3": + model = op_add_species(model) + elif choice == "4": + model = op_remove_species(model) + elif choice == "5": + model = op_keep_species(model) + elif choice == "6": + show_model_info(model) + elif choice == "7": + op_export(model, nep_path) + else: + print(" Invalid option, try again.") + + +if __name__ == "__main__": + print_dependency_notice() + main() diff --git a/Scripts/utils/renumber_atoms.py b/Scripts/utils/renumber_atoms.py index 004897d..b42f040 100644 --- a/Scripts/utils/renumber_atoms.py +++ b/Scripts/utils/renumber_atoms.py @@ -2,19 +2,36 @@ Renumber atom IDs in a LAMMPS dump file. Usage: + gpumdkit.sh -re_atoms python renumber_atoms.py +Arguments: + input_file Input LAMMPS dump file + output_file Output LAMMPS dump file with renumbered atom IDs + +Example: + gpumdkit.sh -re_atoms dump.lammps dump_renumbered.lammps + Author: - Dian HUANG + Dian HUANG (huangdian@stu.xjtu.edu.cn) """ import sys -from tqdm import tqdm -# Check command-line arguments -if len(sys.argv) != 3: - print("Usage: python renumber_atoms.py ") - sys.exit(1) +args = sys.argv[1:] +if len(args) < 2 or args[0] in ("-h", "--help"): + print(" Usage: gpumdkit.sh -re_atoms ") + print(" or: python renumber_atoms.py ") + print("") + print(" Arguments:") + print(" input_file Input LAMMPS dump file") + print(" output_file Output LAMMPS dump file with renumbered atom IDs") + print("") + print(" Example: gpumdkit.sh -re_atoms dump.lammps dump_renumbered.lammps") + print("") + sys.exit(0 if args and args[0] in ("-h", "--help") else 1) + +from tqdm import tqdm input_file = sys.argv[1] output_file = sys.argv[2] diff --git a/Scripts/utils/update_gpumdkit.sh b/Scripts/utils/update_gpumdkit.sh index da7e1ee..237e422 100644 --- a/Scripts/utils/update_gpumdkit.sh +++ b/Scripts/utils/update_gpumdkit.sh @@ -1,21 +1,24 @@ # check for updates function update_gpumdkit(){ +# Save the caller's working directory so it can be restored on success. +__update_orig_pwd="$PWD" + # Check if in a Git repository; if not, try to switch to GPUMDkit_path if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then if [ -z "$GPUMDkit_path" ]; then - echo "Error: Not in a Git repository and GPUMDkit_path environment variable is not set." + echo " Error: Not in a Git repository and GPUMDkit_path environment variable is not set." exit 1 fi if [ ! -d "$GPUMDkit_path" ]; then - echo "Error: Directory $GPUMDkit_path does not exist." + echo " Error: Directory $GPUMDkit_path does not exist." exit 1 fi cd "$GPUMDkit_path" || { - echo "Error: Failed to change directory to $GPUMDkit_path." + echo " Error: Failed to change directory to $GPUMDkit_path." exit 1 } if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then - echo "Error: $GPUMDkit_path is not a Git repository." + echo " Error: $GPUMDkit_path is not a Git repository." exit 1 fi fi @@ -23,7 +26,7 @@ fi # Get current branch name current_branch=$(git rev-parse --abbrev-ref HEAD) if [ -z "$current_branch" ]; then - echo "Error: Unable to determine current branch." + echo " Error: Unable to determine current branch." exit 1 fi @@ -35,34 +38,27 @@ remote_commit=$(git ls-remote https://github.com/zhyan0603/GPUMDkit.git "$curren # Check if remote commit was retrieved successfully if [ -z "$remote_commit" ]; then - echo "Error: Unable to fetch remote repository information." - echo "Check network or branch name ($current_branch)." + echo " Error: Unable to fetch remote repository information." + echo " Check network or branch name ($current_branch)." exit 1 fi # Compare local and remote commits if [ "$local_commit" = "$remote_commit" ]; then - echo "No updates available: Local $current_branch branch is up to date." + echo " No updates available: Local $current_branch branch is up to date." else - echo "Updates detected, pulling latest code for branch $current_branch..." - # Update permissions and pull code - if [ -f "gpumdkit.sh" ]; then - chmod -x gpumdkit.sh - else - echo "Warning: gpumdkit.sh not found, skipping permission change." - fi + echo " Updates detected, pulling latest code for branch $current_branch..." # Pull latest code if git pull origin "$current_branch"; then - echo "Code successfully updated." - # Restore executable permission for gpumdkit.sh - if [ -f "gpumdkit.sh" ]; then - chmod +x gpumdkit.sh - echo "Restored executable permission for gpumdkit.sh." - fi + echo " Code successfully updated." else - echo "Error: Failed to pull code. Check Git configuration or network connection." + echo " Error: Failed to pull code. Check Git configuration or network connection." + cd "$__update_orig_pwd" 2>/dev/null exit 1 fi fi + +# Restore the caller's working directory on success. +cd "$__update_orig_pwd" 2>/dev/null } \ No newline at end of file diff --git a/Scripts/workflow/README.md b/Scripts/workflow/README.md index 1d9d743..60d7ab8 100644 --- a/Scripts/workflow/README.md +++ b/Scripts/workflow/README.md @@ -7,7 +7,7 @@ Workflow scripts automate repetitive tasks in computational materials research: -- **SCF Batch preprocessin**: Set up VASP/CP2K single-point energy calculations +- **SCF batch preprocessing**: Set up VASP/CP2K single-point energy calculations - **MD sampling**: Prepare molecular dynamics simulations with GPUMD/LAMMPS - **Active learning**: Iterative NEP model improvement workflows @@ -24,14 +24,16 @@ Access workflow tools through `gpumdkit.sh` interactive mode: | |_| | __/| |_| | | | | |_| | <| | |_ \____|_| \___/|_| |_|____/|_|\_\_|\__| - GPUMDkit Version 1.4.2 (dev) (2025-12-17) + GPUMDkit Version 1.5.6 (dev) (2026-06-17) Core Developer: Zihan YAN (yanzihan@westlake.edu.cn) + Main Contributors: Denan LI, Xin WU, Zhoulin LIU & Chen HUA ----------------------- GPUMD ----------------------- - 1) Format Conversion 2) Sample Structures - 3) Workflow 4) Calculators - 5) Analyzer 6) Developing ... - 0) Quit! + 1) Format Conversion 2) Sample Structures + 3) Workflow 4) Calculators + 5) Analyzer 6) Visualization + 7) Utilities 8) Help + 0) Exit ------------>> Input the function number: 3 @@ -46,6 +48,47 @@ Access workflow tools through `gpumdkit.sh` interactive mode: --- +## Workflow Entries + +### 301) SCF batch pretreatment + +This entry prepares folders for single-point calculations. For VASP, keep either `.vasp` structures or one `.xyz` file in the current directory before running the script. + +- If `.vasp` files are present, the script processes the `.vasp` files. +- If both `.vasp` and `.xyz` files are present, the script prints a notice and only processes `.vasp` files. +- If no `.vasp` file is present and multiple `.xyz` files are detected, the script asks which `.xyz` file to process. + +After running, the script creates `struct_fp/`, `fp/`, and `fp_sample_*` directories. Put `INCAR`, `POTCAR`, and `KPOINTS` into the generated `fp/` directory; each calculation folder links to these files. + +For CP2K, enter `3) Workflow`, then `301) SCF batch pretreatment`, and choose the CP2K branch. The CP2K script asks for: + +```text + +``` + +The repository provides `Scripts/workflow/cp2k_template.inp` as a starting template. + + + +### 302) MD sample batch pretreatment (GPUMD) + +This entry prepares GPUMD MD sampling folders. Start from `.vasp` structures, or from one selected `.xyz` trajectory/structure file if no `.vasp` files are present. + +- If `.vasp` files are present, they are converted to extxyz files and processed. +- If both `.vasp` and `.xyz` files are present, only `.vasp` files are processed. +- If multiple `.xyz` files are detected without `.vasp` files, the script asks which one to use. + +After running, put `nep.txt` and `run_*.in` files into the generated `md/` directory. The sample folders link `run_1.in`, `run_2.in`, ... as their `run.in`. + + + +### 303) MD sample batch pretreatment (LAMMPS) + +This entry prepares LAMMPS MD sampling folders. The input-file selection rules are the same as function 302. + +After running, put `lmprun.in` and `nep.txt` into the generated `md/` directory. The sample folders link `lammps.data`, `lmprun.in`, and `nep.txt`. + + ### workflow_active_learning_dev.sh Implements automated active learning cycles for iterative NEP model improvement. diff --git a/Scripts/workflow/md_sample_batch_pretreatment_gpumd.sh b/Scripts/workflow/md_sample_batch_pretreatment_gpumd.sh index 79de851..47df30a 100644 --- a/Scripts/workflow/md_sample_batch_pretreatment_gpumd.sh +++ b/Scripts/workflow/md_sample_batch_pretreatment_gpumd.sh @@ -3,7 +3,7 @@ # GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP # Repository: https://github.com/zhyan0603/GPUMDkit # Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, -# MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) +# MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) # ============================================================================= # Script: md_sample_batch_pretreatment_gpumd.sh # Category: Workflow Scripts @@ -26,6 +26,10 @@ function f302_md_sample_batch_pretreatment_gpumd(){ # Check if there are any .vasp files if [ $num_vasp_files -gt 0 ]; then + if [ $num_xyz_files -gt 0 ]; then + echo " Notice: Found both .vasp and .xyz files in the current directory." + echo " This workflow prioritizes .vasp files and will ignore .xyz files." + fi # Create the struct directory and move .vasp files into it mkdir -p struct_md rename_seq=1 @@ -44,11 +48,23 @@ function f302_md_sample_batch_pretreatment_gpumd(){ done num_xyz_files=$(find ./struct_md -maxdepth 1 -name "*.xyz" | wc -l) else - # Check if there is exactly one XYZ file - if [ $num_xyz_files -eq 1 ]; then - echo " No .vasp files found, but found one XYZ file." - echo " Converting it to model.xyz using GPUMDkit..." - python ${GPUMDkit_path}/Scripts/format_conversion/split_single_xyz.py *.xyz + # Check available XYZ files + if [ $num_xyz_files -ge 1 ]; then + if [ $num_xyz_files -eq 1 ]; then + xyz_file=$(find . -maxdepth 1 -name "*.xyz" | head -n 1) + echo " No .vasp files found, but found one XYZ file: ${xyz_file#./}" + else + echo " No .vasp files found, but found multiple XYZ files:" + select xyz_file in *.xyz; do + if [ -n "$xyz_file" ]; then + break + fi + echo " Invalid selection. Please choose one XYZ file." + done + [ -n "$xyz_file" ] || { echo " Input closed. Exiting."; return 1; } + fi + echo " Splitting ${xyz_file#./} to model_*.xyz using GPUMDkit..." + python ${GPUMDkit_path}/Scripts/format_conversion/split_single_xyz.py "$xyz_file" mkdir -p struct_md mv *.xyz ./struct_md @@ -56,8 +72,8 @@ function f302_md_sample_batch_pretreatment_gpumd(){ # Perform additional operations if needed after moving .vasp files else - echo " No .vasp files found and the XYZ file is not unique." - exit 1 + echo " No .vasp files or .xyz files found." + return 1 fi fi @@ -66,7 +82,7 @@ function f302_md_sample_batch_pretreatment_gpumd(){ # Ask user for directory name prefix echo " >-------------------------------------------------<" echo " | This function calls the script in Scripts |" - echo " | Script: md_sample_batch_pretreatment.sh |" + echo " | Script: md_sample_batch_pretreatment_gpumd.sh |" echo " | Developer: Zihan YAN (yanzihan@westlake.edu.cn) |" echo " >-------------------------------------------------<" @@ -84,7 +100,7 @@ function f302_md_sample_batch_pretreatment_gpumd(){ cd .. done - # Create the presub.sh file for VASP self-consistency calculations + # Create the presub.sh file for GPUMD MD sampling cat > presub.sh <<-EOF #!/bin/bash @@ -101,13 +117,13 @@ function f302_md_sample_batch_pretreatment_gpumd(){ # Make presub.sh executable chmod +x presub.sh - echo " >----------------------------------------------------<" - echo " | ATTENTION: Place run_*.in and nep.txt in 'md' Dir. |" - echo " >----------------------------------------------------<" - echo " | You need to provide MD control parameter files in |" - echo " | the format run_*.in (e.g., run_1.in, run_2.in), |" - echo " | each corresponding to a sample (e.g., sample_1, |" - echo " | sample_2) for molecular dynamics simulations. |" - echo " >----------------------------------------------------<" + echo " >---------------------------------------------------------<" + echo " | ATTENTION: Place run_*.in and nep.txt in 'md' Dir. |" + echo " >---------------------------------------------------------<" + echo " | You need to provide MD control parameter files in |" + echo " | the format run_*.in (e.g., run_1.in, run_2.in), |" + echo " | each corresponding to a sample (e.g., sample_1, |" + echo " | sample_2) for molecular dynamics simulations. |" + echo " >---------------------------------------------------------<" } diff --git a/Scripts/workflow/md_sample_batch_pretreatment_lmp.sh b/Scripts/workflow/md_sample_batch_pretreatment_lmp.sh index da809bd..c319640 100644 --- a/Scripts/workflow/md_sample_batch_pretreatment_lmp.sh +++ b/Scripts/workflow/md_sample_batch_pretreatment_lmp.sh @@ -3,7 +3,7 @@ # GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP # Repository: https://github.com/zhyan0603/GPUMDkit # Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, -# MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) +# MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) # ============================================================================= # Script: md_sample_batch_pretreatment_lmp.sh # Category: Workflow Scripts @@ -26,6 +26,10 @@ function f303_md_sample_batch_pretreatment_lmp(){ # Check if there are any .vasp files if [ $num_vasp_files -gt 0 ]; then + if [ $num_xyz_files -gt 0 ]; then + echo " Notice: Found both .vasp and .xyz files in the current directory." + echo " This workflow prioritizes .vasp files and will ignore .xyz files." + fi # Create the struct directory and move .vasp files into it mkdir -p struct_md rename_seq=1 @@ -46,11 +50,23 @@ function f303_md_sample_batch_pretreatment_lmp(){ done num_lmp_files=$(find ./struct_md -maxdepth 1 -name "*.data" | wc -l) else - # Check if there is exactly one XYZ file - if [ $num_xyz_files -eq 1 ]; then - echo " No .vasp files found, but found one XYZ file." - echo " Converting it to model.xyz using GPUMDkit..." - python ${GPUMDkit_path}/Scripts/format_conversion/split_single_xyz.py *.xyz + # Check available XYZ files + if [ $num_xyz_files -ge 1 ]; then + if [ $num_xyz_files -eq 1 ]; then + xyz_file=$(find . -maxdepth 1 -name "*.xyz" | head -n 1) + echo " No .vasp files found, but found one XYZ file: ${xyz_file#./}" + else + echo " No .vasp files found, but found multiple XYZ files:" + select xyz_file in *.xyz; do + if [ -n "$xyz_file" ]; then + break + fi + echo " Invalid selection. Please choose one XYZ file." + done + [ -n "$xyz_file" ] || { echo " Input closed. Exiting."; return 1; } + fi + echo " Splitting ${xyz_file#./} to model_*.xyz using GPUMDkit..." + python ${GPUMDkit_path}/Scripts/format_conversion/split_single_xyz.py "$xyz_file" mkdir -p struct_md mv *.xyz ./struct_md @@ -69,8 +85,8 @@ function f303_md_sample_batch_pretreatment_lmp(){ # Perform additional operations if needed after moving .vasp files else - echo " No .vasp files found and the XYZ file is not unique." - exit 1 + echo " No .vasp files or .xyz files found." + return 1 fi fi @@ -96,7 +112,7 @@ function f303_md_sample_batch_pretreatment_lmp(){ cd .. done - # Create the presub.sh file for VASP self-consistency calculations + # Create the presub.sh file for LAMMPS MD sampling cat > presub.sh <<-EOF #!/bin/bash @@ -113,9 +129,9 @@ function f303_md_sample_batch_pretreatment_lmp(){ # Make presub.sh executable chmod +x presub.sh - echo " >--------------------------------------------------<" - echo " ATTENTION: Place lmprun.in and nep.txt in 'md' Dir. " - echo " ATTENTION: Place lmprun.in and nep.txt in 'md' Dir. " - echo " ATTENTION: Place lmprun.in and nep.txt in 'md' Dir. " - echo " >--------------------------------------------------<" + echo " >---------------------------------------------------------<" + echo " | ATTENTION: Place lmprun.in and nep.txt in 'md' Dir. |" + echo " | ATTENTION: Place lmprun.in and nep.txt in 'md' Dir. |" + echo " | ATTENTION: Place lmprun.in and nep.txt in 'md' Dir. |" + echo " >---------------------------------------------------------<" } diff --git a/Scripts/workflow/scf_batch_pretreatment_cp2k.py b/Scripts/workflow/scf_batch_pretreatment_cp2k.py index 70037e0..96d82aa 100644 --- a/Scripts/workflow/scf_batch_pretreatment_cp2k.py +++ b/Scripts/workflow/scf_batch_pretreatment_cp2k.py @@ -3,19 +3,20 @@ GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP Repository: https://github.com/zhyan0603/GPUMDkit Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, - MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) + MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) ============================================================================= Script: scf_batch_pretreatment_cp2k.py Category: Workflow Scripts Purpose: Batch pretreatment of structures for CP2K SCF calculations. Reads structures from extxyz/VASP files, copies a CP2K template, and populates the CELL section with the correct lattice vectors. -Usage: python scf_batch_pretreatment_cp2k.py [template] +Usage: python scf_batch_pretreatment_cp2k.py Arguments: - xyz_file Input extxyz file with structures - template (optional) CP2K input template (default: cp2k_template.inp) + extxyz_file Input extxyz file with structures + template_inp CP2K input template + prefix Prefix for output directories Output: - struct_fp/ directory with POSCAR_*.vasp and cp2k input files + _/ directories with input.inp and pos.xyz files Author: Zihan YAN (yanzihan@westlake.edu.cn) Last-modified: 2026-05-16 ============================================================================= diff --git a/Scripts/workflow/scf_batch_pretreatment_vasp.sh b/Scripts/workflow/scf_batch_pretreatment_vasp.sh index bd42d44..aeb1297 100644 --- a/Scripts/workflow/scf_batch_pretreatment_vasp.sh +++ b/Scripts/workflow/scf_batch_pretreatment_vasp.sh @@ -3,7 +3,7 @@ # GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP # Repository: https://github.com/zhyan0603/GPUMDkit # Citation: Z. Yan et al., GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP, -# MGE Advances, 2026, e70074 (https://doi.org/10.1002/mgea.70074) +# MGE Advances, 2026, 4, e70074 (https://doi.org/10.1002/mgea.70074) # ============================================================================= # Script: scf_batch_pretreatment_vasp.sh # Category: Workflow Scripts @@ -26,6 +26,10 @@ function vasp_scf_batch_pretreatment(){ # Check if there are any .vasp files if [ $num_vasp_files -gt 0 ]; then + if [ $num_xyz_files -gt 0 ]; then + echo " Notice: Found both .vasp and .xyz files in the current directory." + echo " This workflow prioritizes .vasp files and will ignore .xyz files." + fi # Create the struct directory and move .vasp files into it mkdir -p struct_fp rename_seq=1 @@ -36,11 +40,23 @@ function vasp_scf_batch_pretreatment(){ done num_vasp_files=$(find ./struct_fp -maxdepth 1 -name "*.vasp" | wc -l) else - # Check if there is exactly one XYZ file - if [ $num_xyz_files -eq 1 ]; then - echo " No .vasp files found, but found one XYZ file." - echo " Converting it to POSCAR using GPUMDkit..." - python ${GPUMDkit_path}/Scripts/format_conversion/exyz2pos.py *.xyz + # Check available XYZ files + if [ $num_xyz_files -ge 1 ]; then + if [ $num_xyz_files -eq 1 ]; then + xyz_file=$(find . -maxdepth 1 -name "*.xyz" | head -n 1) + echo " No .vasp files found, but found one XYZ file: ${xyz_file#./}" + else + echo " No .vasp files found, but found multiple XYZ files:" + select xyz_file in *.xyz; do + if [ -n "$xyz_file" ]; then + break + fi + echo " Invalid selection. Please choose one XYZ file." + done + [ -n "$xyz_file" ] || { echo " Input closed. Exiting."; return 1; } + fi + echo " Converting ${xyz_file#./} to POSCAR files using GPUMDkit..." + python ${GPUMDkit_path}/Scripts/format_conversion/exyz2pos.py "$xyz_file" mkdir -p struct_fp mv *.vasp ./struct_fp @@ -48,8 +64,8 @@ function vasp_scf_batch_pretreatment(){ # Perform additional operations if needed after moving .vasp files else - echo " No .vasp files found and the XYZ file is not unique." - exit 1 + echo " No .vasp files or .xyz files found." + return 1 fi fi @@ -58,7 +74,7 @@ function vasp_scf_batch_pretreatment(){ # Ask user for directory name prefix echo " >-------------------------------------------------<" echo " | This function calls the script in Scripts |" - echo " | Script: scf_batch_pretreatment.sh |" + echo " | Script: scf_batch_pretreatment_vasp.sh |" echo " | Developer: Zihan YAN (yanzihan@westlake.edu.cn) |" echo " >-------------------------------------------------<" echo " We recommend using the prefix to locate the structure." @@ -66,7 +82,7 @@ function vasp_scf_batch_pretreatment(){ echo " config_type=_" echo " ------------>>" echo " Please enter the prefix of directory (e.g. FAPBI3_iter01)" - read -p " " prefix + read_menu_choice prefix || return 1 # Create fp directory mkdir -p fp @@ -98,9 +114,9 @@ function vasp_scf_batch_pretreatment(){ # Make presub.sh executable chmod +x presub.sh - echo " >-----------------------------------------------------<" - echo " ATTENTION: Place POTCAR, KPOINTS and INCAR in 'fp' Dir." - echo " ATTENTION: Place POTCAR, KPOINTS and INCAR in 'fp' Dir." - echo " ATTENTION: Place POTCAR, KPOINTS and INCAR in 'fp' Dir." - echo " >-----------------------------------------------------<" + echo " >---------------------------------------------------------<" + echo " | ATTENTION: Place POTCAR, KPOINTS and INCAR in 'fp' Dir. |" + echo " | ATTENTION: Place POTCAR, KPOINTS and INCAR in 'fp' Dir. |" + echo " | ATTENTION: Place POTCAR, KPOINTS and INCAR in 'fp' Dir. |" + echo " >---------------------------------------------------------<" } diff --git a/Scripts/workflow/submit_template.sh b/Scripts/workflow/submit_template.sh index 5227816..924fe19 100644 --- a/Scripts/workflow/submit_template.sh +++ b/Scripts/workflow/submit_template.sh @@ -1,4 +1,4 @@ -#!bin/bash +#!/bin/bash function submit_gpumd_array(){ cat > submit.slurm <<-EOF diff --git a/Scripts/workflow/workflow_active_learning_dev.sh b/Scripts/workflow/workflow_active_learning_dev.sh index 356d860..a6bb63f 100644 --- a/Scripts/workflow/workflow_active_learning_dev.sh +++ b/Scripts/workflow/workflow_active_learning_dev.sh @@ -11,7 +11,7 @@ cd $SLURM_SUBMIT_DIR # It is recommended that you copy it to another path, # otherwise there will be code conflicts when use 'git pull' command to update GPUMDkit. source ${GPUMDkit_path}/Scripts/workflow/submit_template.sh -python_pynep=/storage/zhuyizhouLab/yanzhihan/soft/conda/envs/gpumd/bin/python # python executable for pynep +python_pynep=python # python executable for deprecated pynep branch if needed work_dir=${PWD} # work directory prefix_name=LiF_iter01 # prefix name for this workflow, used for the scf calculations @@ -117,7 +117,7 @@ case $sample_method in "pynep") echo $(date -d "2 second" +"%Y-%m-%d %H:%M:%S") "Performing pynep sampling..." # This function still needs to be improved in the future. - (echo 202; echo "filtered_by_box.xyz train.xyz nep.txt"; echo 1; echo ${pynep_sample_dist}) | gpumdkit.sh >> /dev/null + (echo "filtered_by_box.xyz train.xyz nep.txt 1"; echo 1; echo ${pynep_sample_dist}) | gpumdkit.sh -pynep >> /dev/null #${python_pynep} ${GPUMDkit_path}/Scripts/sample_structures/pynep_select_structs.py filtered_by_box.xyz train.xyz nep.txt ${pynep_sample_dist} # Check the number of structures in selected.xyz selected_struct_num=$(grep -c Lat selected.xyz) @@ -178,4 +178,3 @@ submit_nep_prediction sbatch submit.slurm gpumdkit.sh -plt prediction save echo $(date -d "2 second" +"%Y-%m-%d %H:%M:%S") "Prediction finished." - diff --git a/Scripts/workflow/workflow_active_learning_dev_multielement.sh b/Scripts/workflow/workflow_active_learning_dev_multielement.sh index 9f7513e..1fb698b 100644 --- a/Scripts/workflow/workflow_active_learning_dev_multielement.sh +++ b/Scripts/workflow/workflow_active_learning_dev_multielement.sh @@ -11,7 +11,7 @@ cd $SLURM_SUBMIT_DIR # It is recommended that you copy it to another path, # otherwise there will be code conflicts when use 'git pull' command to update GPUMDkit. source ${GPUMDkit_path}/Scripts/workflow/submit_template.sh -python_pynep=/storage/zhuyizhouLab/yanzhihan/soft/conda/envs/gpumd/bin/python # python executable for pynep +python_pynep=python # python executable for deprecated pynep branch if needed work_dir=${PWD} # work directory prefix_name=LiF_iter01 # prefix name for this workflow, used for the scf calculations @@ -117,7 +117,7 @@ case $sample_method in "pynep") echo $(date -d "2 second" +"%Y-%m-%d %H:%M:%S") "Performing pynep sampling..." # This function still needs to be improved in the future. - (echo 202; echo "filtered_by_box.xyz train.xyz nep.txt"; echo 1; echo ${pynep_sample_dist}) | gpumdkit.sh >> /dev/null + (echo "filtered_by_box.xyz train.xyz nep.txt 1"; echo 1; echo ${pynep_sample_dist}) | gpumdkit.sh -pynep >> /dev/null #${python_pynep} ${GPUMDkit_path}/Scripts/sample_structures/pynep_select_structs.py filtered_by_box.xyz train.xyz nep.txt ${pynep_sample_dist} # Check the number of structures in selected.xyz selected_struct_num=$(grep -c Lat selected.xyz) @@ -179,4 +179,3 @@ submit_nep_prediction sbatch submit.slurm gpumdkit.sh -plt prediction save echo $(date -d "2 second" +"%Y-%m-%d %H:%M:%S") "Prediction finished." - diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 0000000..306eef6 --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +gpumdkit.cn diff --git a/docs/CONTRIBUTING_zh-CN.md b/docs/CONTRIBUTING_zh-CN.md new file mode 100644 index 0000000..3ff14e1 --- /dev/null +++ b/docs/CONTRIBUTING_zh-CN.md @@ -0,0 +1,443 @@ +# 为 GPUMDkit 贡献代码 + +

+ English +  ·  + 简体中文 +

+ +感谢你有兴趣为 `GPUMDkit` 做出贡献!我们感谢你为改善这个工具包所付出的时间和努力。`GPUMDkit` 是一个开源项目,我们欢迎社区的各种贡献,无论是修复 bug、添加新功能、改进文档还是提出建议。 + +--- + +## 目录 + +- [开发规范与准则](#开发规范与准则) +- [报告问题](#报告问题) +- [功能建议](#功能建议) +- [贡献代码](#贡献代码) + - [Fork 并克隆仓库](#fork-并克隆仓库) + - [创建功能分支](#创建功能分支) + - [进行修改](#进行修改) + - [交互模式贡献](#交互模式贡献) + - [命令行模式贡献](#命令行模式贡献) + - [更新 Tab 补全](#更新-tab-补全) + - [代码风格与最佳实践](#代码风格与最佳实践) + - [测试你的修改](#测试你的修改) + - [提交信息](#提交信息) + - [推送并创建 Pull Request](#推送并创建-pull-request) + +--- + +## 开发规范与准则 + +为保持代码质量和项目一致性,请遵循以下准则: + +### 语言要求 + +- **所有代码应使用英文编写**:包括变量名、函数名、注释、文档字符串、提交信息和文档。 +- 虽然我们理解贡献者来自不同背景,但使用英文能确保代码库对最广泛的用户群体可访问。 + +### 模块化与可复用性 + +- **编写模块化和可复用的代码**:函数和脚本的设计应具有灵活性。 +- **优先传递参数而非硬编码值**:使用函数参数、命令行参数或配置文件来替代硬编码值。但某些文件名由 GPUMD 和 NEP 程序固定要求(如 `train.xyz`、`thermo.out`),这些可以按需硬编码。 +- **示例**: + ```bash + # 好的做法:接受参数 + function convert_file() { + local input_file=$1 + local output_file=$2 + # 处理逻辑 + } + + # 避免:硬编码值(除非 GPUMD/NEP 要求) + function convert_file() { + local input_file="hardcoded_input.xyz" + # 处理逻辑 + } + ``` + +### 代码风格 + +- 编写清晰、易于他人维护和修改的代码。 +- 使用有意义的变量和函数名。 +- 在必要处添加注释以解释复杂逻辑。 + +### 文档 + +- 确保帮助信息(如 `-h` 标志)清晰准确。 +- 教程文档位于 `docs/tutorials/en/`(英文)和 `docs/tutorials/zh/`(中文)。如果你添加了新功能,请考虑更新相关教程页面。 +- 编辑教程 Markdown 文件后,使用 `mkdocs build -f docs/mkdocs.yml` 重新构建 HTML。 + +--- + +## 报告问题 + +如果你遇到 bug,请通过 GitHub Issues 帮助我们修复: + +1. **搜索现有 issues** 查看该 bug 是否已被报告。 +2. **创建新 issue**(如果尚未被报告):[创建 Issue](https://github.com/zhyan0603/GPUMDkit/issues/new) +3. **详细描述问题**,如果可能请提供测试文件。 + +你也可以通过以下方式联系我们: +- **QQ 群**:825696376 +- **邮箱**:yanzihan@westlake.edu.cn +- **脚本开发者**:联系脚本头部列出的开发者 + +--- + +## 功能建议 + +我们欢迎功能建议!提出新功能: + +1. **搜索现有 issues** 查看是否已有人提出。 +2. **创建新功能请求**:[创建功能请求](https://github.com/zhyan0603/GPUMDkit/issues/new) 并 mention @zhyan0603 +3. **清楚描述你的需求** 并解释其用途。 + +--- + +## 贡献代码 + +### Fork 并克隆仓库 + +1. 在 GitHub 上 **Fork 仓库**,点击 [仓库页面](https://github.com/zhyan0603/GPUMDkit) 右上角的 "Fork" 按钮。 + +2. **克隆你的 fork** 到本地: + + ```bash + git clone https://github.com/YOUR_USERNAME/GPUMDkit.git + cd GPUMDkit + ``` + +3. **设置 upstream remote** 以保持 fork 同步: + ```bash + git remote add upstream https://github.com/zhyan0603/GPUMDkit.git + ``` + +### 创建功能分支 + +为你的修改创建新分支: + +```bash +# 从 main 创建并切换到新分支 +git checkout -b your-branch-name +``` + +分支名称随意。 + +### 进行修改 + +`GPUMDkit` 的结构包括: +- **`gpumdkit.sh`**:主入口(Bash 脚本),处理交互菜单模式和命令行模式 +- **`install.sh`**:安装脚本,设置环境变量和 shell 配置 +- **`Scripts/`**:按功能组织的 Python 和 Bash 实现脚本 + - `plt_scripts/`:绘图脚本 + - `calculators/`:计算工具 + - `format_conversion/`:格式转换工具 + - `workflow/`:工作流自动化 + - `sample_structures/`:结构采样工具 + - `analyzer/`:分析工具 + - `utils/`:实用函数(包括 `completion.sh` Tab 补全) +- **`src/`**:交互模式菜单函数的 Shell 脚本 + - `f1_format_conversions.sh` + - `f2_sample_structures.sh` + - `f3_workflows.sh` + - `f4_calculators.sh` + - `f5_analyzers.sh` + - `f6_plots.sh` + - `f7_utilities.sh` +- **`skills/`**:AI agent 技能定义(用于 opencode/Claude Code 集成的 SKILL.md 文件) +- **`docs/`**:文档文件 + - `tutorials/en/` 和 `tutorials/zh/`:双语教程页面 + - `mkdocs.yml`:构建教程 HTML 的 MkDocs 配置 + - `command_reference.tsv`:机器可读的命令参考 + - `htmls/`:MkDocs 生成的 HTML 输出 + +#### 交互模式贡献 + +要添加通过交互菜单访问的新功能: + +1. **在相应的 `Scripts/` 子目录中创建实现脚本**: + + ```bash + # 示例:添加新的格式转换脚本 + touch Scripts/format_conversion/new_converter.py + ``` + +2. **实现你的功能**,遵循模块化准则(接受参数,避免硬编码)。 + +3. **在相应的 `src/` 文件中添加包装函数**: + ```bash + # 示例:编辑 src/f1_format_conversions.sh + vim src/f1_format_conversions.sh + ``` + + 添加新函数: + ```bash + function f111_new_converter(){ + echo " >-------------------------------------------------<" + echo " | Calling the script in Scripts/format_conversion |" + echo " | Script: new_converter.py |" + echo " | Developer: Your Name (your@email.com) |" + echo " >-------------------------------------------------<" + echo " Input " + echo " Example: input.xyz output.lmp" + echo " ------------>>" + read -r -a converter_args + echo " ---------------------------------------------------" + python ${GPUMDkit_path}/Scripts/format_conversion/new_converter.py "${converter_args[@]}" + echo " Code path: ${GPUMDkit_path}/Scripts/format_conversion/new_converter.py" + echo " ---------------------------------------------------" + } + ``` + +4. **在 `gpumdkit.sh` 中更新菜单显示**: + ```bash + # 找到 menu() 函数并按需更新 + # 找到 array_choice 数组并添加你的新选择编号 + array_choice=( + "0" "1" "101" "102" "103" "104" "105" "106" "107" "108" "109" "110" "111" # 添加 "111" + # ... 其余选择 + ) + ``` + +5. **在 `gpumdkit.sh` 中添加 case 语句**: + ```bash + # 在 main() 函数中找到相应的 case 语句 + case "${choice:0:1}" in + # ... + "1") + source ${GPUMDkit_path}/src/f1_format_conversions.sh + case $choice in + "1") f1_format_conversion ;; + "101") f101_out2xyz ;; + # ... 现有 case ... + "111") f111_new_converter ;; # 添加你的 case + esac ;; + # ... + esac + ``` + +#### 命令行模式贡献 + +要添加新的命令行标志或子命令: + +1. **在相应的 `Scripts/` 子目录中创建实现脚本**: + ```bash + # 示例:添加新的分析器脚本 + touch Scripts/analyzer/analyze_bonds.py + ``` + +2. **实现你的功能**,明确参数要求: + ```python + # 示例:Scripts/analyzer/analyze_bonds.py + import sys + + if len(sys.argv) != 3: + print("Usage: gpumdkit.sh -analyze_bonds ") + print("Example: gpumdkit.sh -analyze_bonds structure.xyz 3.0") + sys.exit(1) + + input_file = sys.argv[1] + cutoff = float(sys.argv[2]) + + # 你的实现 + ``` + + > **注意**:GPUMDkit Python 脚本设计为直接运行(不作为模块导入)。 + > 如果你愿意,可以使用 `main()` 函数配合 `if __name__ == "__main__":` 保护, + > 但这不是必需的。大多数现有脚本在模块级别执行。 + +3. **在 `gpumdkit.sh` 中添加命令行标志处理**: + ```bash + # 找到命令行解析部分(大的 "case $1 in" 块) + # 在适当位置添加你的新标志 + + case $1 in + # ... 现有 case ... + -analyze_bonds) + if [ ! -z "$2" ] && [ "$2" != "-h" ] && [ ! -z "$3" ]; then + python ${analyzer_path}/analyze_bonds.py $2 $3 + else + echo " Usage: gpumdkit.sh -analyze_bonds " + echo " Example: gpumdkit.sh -analyze_bonds structure.xyz 3.0" + echo " Code path: ${analyzer_path}/analyze_bonds.py" + fi ;; + # ... 其余 case ... + esac + ``` + +4. **在 `gpumdkit.sh` 中更新帮助信息**: + ```bash + # 找到 help_info_table() 函数并添加你的命令 + function help_info_table(){ + echo "+====================================== Analysis ===============================================+" + echo "| -analyze_bonds Analyze bond lengths in struct | -analyze_comp Analyze composition of extxyz |" + # ... 其余帮助表 ... + } + ``` + +#### 更新 Tab 补全 + +添加新的命令行标志时,更新 Tab 补全脚本: + +```bash +# 编辑 Scripts/utils/completion.sh +vim Scripts/utils/completion.sh +``` + +将你的新标志添加到 `opts` 变量: +```bash +# 找到 local opts=... 行 +local opts="-h -help -update -U -clean -time -plt -calc ... -your_new_flag ..." +# 在此添加你的标志 +``` + +如果你的标志需要文件参数,将其添加到现有的文件补全 case 中: +```bash +# 找到需要文件参数的 case 并用 | 添加你的标志 +-out2xyz|-out2exyz|-...|-your_new_flag) + COMPREPLY=($(compgen -f -- "$cur")) ;; +``` + +如果你的标志接受二级选项(如 `-plt` 或 `-calc`),添加新 case: +```bash +case "$prev" in + # ... 现有 case ... + -your_new_flag) + COMPREPLY=($(compgen -W "option1 option2 option3" -- "$cur")) ;; + # ... 其余 case ... +esac +``` + +### 代码风格与最佳实践 + +- **Shell 脚本**: + - 使用 `${variable}` 进行变量展开 + - 使用 `[ ! -z "$var" ]` 进行非空检查(项目约定) + - 交互函数应遵循 banner 格式: + ```bash + echo " >-------------------------------------------------<" + echo " | Calling the script in Scripts/ |" + echo " | Script: .py |" + echo " | Developer: () |" + echo " >-------------------------------------------------<" + ``` + - 使用 `read -r -a varname` 读取多词输入,然后用 `"${varname[@]}"` 传递 + - `src/` 中的 Shell 脚本应以文件头注释块开始: + ```bash + # ============================================================ + # GPUMDkit module + # Repository: https://github.com/zhyan0603/GPUMDkit + # Author: () + # ============================================================ + ``` + +- **Python 脚本**: + - 编写清晰、可维护的代码 + - 使用有意义的变量名 + - 使用 `sys.argv` 进行参数解析(与大多数现有脚本一致) + - 提供清晰的使用信息:`print("Usage: ...")` 和 `print("Example: ...")` + - 如果你的脚本使用重型/特殊包(`NepTrain`、`calorine`、`dpdata`),请添加 + `print_dependency_notice()` 函数以通知用户引用建议 + +### 测试你的修改 + +提交贡献前,运行相关验证命令: + +```bash +# Shell 语法检查(始终运行) +bash -n gpumdkit.sh +find src Scripts -name '*.sh' -exec bash -n {} + + +# Python 语法检查(针对修改的 Python 文件) +python3 -m py_compile path/to/modified_script.py + +# MkDocs 构建(如果修改了文档) +mkdocs build -f docs/mkdocs.yml + +# 检查尾随空格问题 +git diff --check +``` + +然后测试功能: + +1. **测试交互模式**(如适用): + ```bash + gpumdkit.sh + # 导航到你的新功能并充分测试 + ``` + +2. **测试命令行模式**(如适用): + ```bash + gpumdkit.sh -your_new_flag [arguments] + gpumdkit.sh -your_new_flag -h # 测试帮助信息 + ``` + +3. **测试 Tab 补全**(如果你修改了 `completion.sh`): + ```bash + source Scripts/utils/completion.sh + gpumdkit.sh - # 应显示你的新标志 + ``` + +4. **用各种输入测试**: + - 用典型输入测试 + - 用边缘情况测试(空文件、大文件等) + - 测试错误处理(缺少文件、无效参数) + +5. **验证无回归**:确保现有功能仍然正常工作。 + +### 提交信息 + +编写清晰、描述性的提交信息来解释你做了什么更改。没有严格的格式要求——只要确保你的信息是可理解的。 + +### 推送并创建 Pull Request + +1. **提交你的修改**: + ```bash + git add . + git commit -m "你的描述性信息" + ``` + +2. **保持你的分支与最新的 `dev` 分支同步**: + ```bash + git fetch origin + git rebase origin/dev + ``` + +3. **推送你的分支**到你的 fork: + ```bash + git push origin your-branch-name + ``` + +4. **创建 Pull Request**: + - 前往 [GPUMDkit 仓库](https://github.com/zhyan0603/GPUMDkit) + - 点击 "Pull Requests" → "New Pull Request" + - 设置目标分支为 `dev` 进行代码审查 + - 设置比较分支为你的功能分支 + - 填写 PR 描述: + - **标题**:简要描述更改 + - **描述**:详细解释更改内容和原因 + - **测试**:描述你如何测试这些更改 + +5. **回应审查反馈**: + - 对建议和建设性批评保持开放 + - 及时进行请求的修改 + - 推送额外提交到你的分支(它们会自动出现在 PR 中) + +6. **批准后**:维护者将合并你的 PR。 + +--- + +## 有问题或需要帮助? + +如果你对贡献有疑问或需要帮助: + +- **发起讨论**:使用 [GitHub Discussions](https://github.com/zhyan0603/GPUMDkit/discussions) 提出一般性问题 +- **在 issue 中提问**:在相关 issue 中评论以获取具体问题的帮助 +- **联系维护者**:联系 README 中列出的核心开发者 + +--- + +再次感谢你为 `GPUMDkit` 做出贡献!你的努力帮助这个工具包为整个 GPUMD 和 NEP 社区变得更好。🚀 diff --git a/README_zh-CN.md b/docs/README_zh-CN.md similarity index 92% rename from README_zh-CN.md rename to docs/README_zh-CN.md index 2c162e0..447d5fe 100644 --- a/README_zh-CN.md +++ b/docs/README_zh-CN.md @@ -1,13 +1,13 @@

- GPUMDkit Logo + GPUMDkit Logo

- English + English  ·  简体中文  ·  Website  ·  - Documentation + Documentation  ·  Gallery   @@ -103,7 +103,7 @@ wget https://github.com/zhyan0603/GPUMDkit/archive/refs/heads/main.zip | |_| | __/| |_| | | | | |_| | <| | |_ \____|_| \___/|_| |_|____/|_|\_\_|\__| - GPUMDkit Version 1.5.5 (dev) (2026-05-10) + GPUMDkit Version 1.5.6 (dev) (2026-06-17) Core Developer: Zihan YAN (yanzihan@westlake.edu.cn) Main Contributors: Denan LI, Xin WU, Zhoulin LIU & Chen HUA @@ -111,7 +111,7 @@ wget https://github.com/zhyan0603/GPUMDkit/archive/refs/heads/main.zip 1) Format Conversion 2) Sample Structures 3) Workflow 4) Calculators 5) Analyzer 6) Visualization - 7) Utilities 8) Developing... + 7) Utilities 8) Help 0) Exit ------------>> Input the function number: @@ -133,7 +133,7 @@ gpumdkit.sh -h ``` +-------------------------------------------------------------------------------------------------------+ -| GPUMDkit 1.5.5 (dev) (2026-05-10) Command Help | +| GPUMDkit 1.5.6 (dev) (2026-06-17) Command Help | +-------------------------------------------------------------------------------------------------------+ | MAIN FUNCTIONS | +-------------------------------------------------------------------------------------------------------+ @@ -159,8 +159,8 @@ gpumdkit.sh -h | -chem_species Analyze chemical species | -cbc Charge balance check | | -min_dist Min distance (no PBC) | -min_dist_pbc Min distance with PBC | | -filter_dist Filter by min_dist (no PBC) | -filter_dist_pbc Filter by min_dist (PBC) | -| -pda Probability density analysis | -hbond Hydrogen-bond analysis | -| -pynep FPS sampling by PyNEP | | +| -pda Probability density analysis | -filter_box Filter by box-edge length | +| -pynep Deprecated PyNEP sampling | -nep_modifier Modify NEP model interactively | +-------------------------------------------------------------------------------------------------------+ | Detailed usage: gpumdkit.sh -

- msd + msd
##### 示例 5:绘制 parity 图 @@ -245,7 +245,7 @@ gpumdkit.sh -plt test ```
- msd + msd
##### 示例 6:绘制 thermo 演化图 @@ -256,7 +256,7 @@ gpumdkit.sh -plt test gpumdkit.sh -plt thermo ``` -![](./docs/Gallery/thermo.png) +![](./Gallery/thermo.png) 如果当前设备不支持显示图形,也可以将图片保存为 PNG: @@ -264,13 +264,13 @@ gpumdkit.sh -plt thermo gpumdkit.sh -plt thermo save ``` -更多详细示例和命令选项请参考我们的[文档](https://zhyan0603.github.io/GPUMDkit/htmls/tutorials.html)。 +更多详细示例和命令选项请参考我们的[文档](https://zhyan0603.github.io/GPUMDkit/)。 #### 自定义命令 `GPUMDkit` 支持通过 `~/.gpumdkit.in` 文件自定义命令。 -你可以在该文件中定义函数来添加自己的快捷命令(例如 `gpumdkit.sh -yourcommand`),从而扩展 `GPUMDkit` 的功能。详细用法请参见[此处](https://zhyan0603.github.io/GPUMDkit/htmls/custom_commands.html)。 +你可以在该文件中定义函数来添加自己的快捷命令(例如 `gpumdkit.sh -yourcommand`),从而扩展 `GPUMDkit` 的功能。详细用法请参见[自定义命令文档](https://zhyan0603.github.io/GPUMDkit/)。 #### Tab 补全支持 @@ -296,4 +296,8 @@ gpumdkit.sh -plt thermo save **GPUMDkit** 是一款面向所有人的开源工具。如果在你的研究或工作中它有所帮助,欢迎 ⭐ [在 GitHub 上给我们点亮 Star](https://github.com/zhyan0603/GPUMDkit)。此外,如果 GPUMDkit 对你的发表工作有贡献,请引用我们的论文: -> Z. Yan\*, D. Li, X. Wu, Z. Liu, C. Hua, B. Situ, H. Yang, S. Tang, B. Tang, Z. Wang, S. Yi, H. Wang, D. Huang, K. Li, Q. Guo, Z. Chen, K. Xu, Y. Wang, Z. Wang, G. Tang, S. Liu, Z. Fan, and Y. Zhu\*. **GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP**. [MGE Advances, 2026, e70074](https://doi.org/10.1002/mgea.70074). +> Z. Yan\*, D. Li, X. Wu, Z. Liu, C. Hua, B. Situ, H. Yang, S. Tang, B. Tang, Z. Wang, S. Yi, H. Wang, D. Huang, K. Li, Q. Guo, Z. Chen, K. Xu, Y. Wang, Z. Wang, G. Tang, S. Liu, Z. Fan, and Y. Zhu\*. **GPUMDkit: A User-Friendly Toolkit for GPUMD and NEP**. [MGE Advances, 2026, 4, e70074](https://doi.org/10.1002/mgea.70074). + +在论文中可以参考类似表述: + +> Data processing and figure generation were performed using GPUMDkit [x]. diff --git a/docs/command_reference.tsv b/docs/command_reference.tsv new file mode 100644 index 0000000..6799d2f --- /dev/null +++ b/docs/command_reference.tsv @@ -0,0 +1,49 @@ +category command syntax description_en description_zh status +main -h gpumdkit.sh -h Show general command help 显示通用命令帮助 stable +main -update gpumdkit.sh -update Update GPUMDkit from GitHub 从 GitHub 更新 GPUMDkit stable +main -clean gpumdkit.sh -clean Clean extra files in current directory 清理当前目录中的冗余文件 stable +format -out2xyz gpumdkit.sh -out2xyz Convert VASP OUTCAR files to extxyz (shell version) 将 VASP OUTCAR 转换为 extxyz(shell 版本) stable +format -out2exyz gpumdkit.sh -out2exyz Convert VASP OUTCAR files to extxyz (Python version) 将 VASP OUTCAR 转换为 extxyz(Python 版本) stable +format -cp2k2xyz gpumdkit.sh -cp2k2xyz Convert CP2K output to xyz/extxyz 转换 CP2K 输出为 xyz/extxyz stable +format -xdat2exyz gpumdkit.sh -xdat2exyz Convert XDATCAR to extxyz 将 XDATCAR 转换为 extxyz stable +format -cif2pos gpumdkit.sh -cif2pos Convert CIF to POSCAR/VASP 将 CIF 转换为 POSCAR/VASP stable +format -cif2exyz gpumdkit.sh -cif2exyz Convert CIF to extxyz 将 CIF 转换为 extxyz stable +format -pos2exyz gpumdkit.sh -pos2exyz Convert POSCAR to extxyz 将 POSCAR 转换为 extxyz stable +format -exyz2pos gpumdkit.sh -exyz2pos Convert extxyz frames to POSCAR files 将 extxyz 帧转换为 POSCAR 文件 stable +format -pos2lmp gpumdkit.sh -pos2lmp Convert POSCAR to LAMMPS data 将 POSCAR 转换为 LAMMPS data stable +format -lmp2exyz gpumdkit.sh -lmp2exyz Convert LAMMPS dump to extxyz 将 LAMMPS dump 转换为 extxyz stable +format -traj2exyz gpumdkit.sh -traj2exyz Convert ASE trajectory to extxyz 将 ASE trajectory 转换为 extxyz stable +format -replicate gpumdkit.sh -replicate a b c Replicate a structure by cell factors 按晶胞倍数扩胞 stable +format -replicate gpumdkit.sh -replicate Replicate a structure toward a target atom count 按目标原子数扩胞 stable +format -addgroup gpumdkit.sh -addgroup Add GPUMD group labels 添加 GPUMD group 标签 stable +format -addweight gpumdkit.sh -addweight Add structure weights to extxyz 为 extxyz 添加结构权重 stable +format -get_frame gpumdkit.sh -get_frame Extract one frame from extxyz 从 extxyz 提取单帧 stable +format -clean_xyz gpumdkit.sh -clean_xyz Remove extra properties from extxyz 清理 extxyz 中的冗余属性 stable +format -frame_range gpumdkit.sh -frame_range Extract frames by fractional range 按比例范围提取帧 stable +sampling -pynep gpumdkit.sh -pynep Run PyNEP FPS sampling 运行 PyNEP FPS 采样 deprecated +calc -calc ionic-cond gpumdkit.sh -calc ionic-cond Calculate ionic conductivity 计算离子电导率 stable +calc -calc nep gpumdkit.sh -calc nep Predict properties with a NEP model 使用 NEP 模型预测性质 stable +calc -calc des gpumdkit.sh -calc des Calculate NEP descriptors 计算 NEP 描述符 stable +calc -calc doas gpumdkit.sh -calc doas Calculate density of atomistic states 计算原子态密度 stable +calc -calc neb gpumdkit.sh -calc neb Run NEB with a NEP model 使用 NEP 模型运行 NEB stable +calc -calc minimize gpumdkit.sh -calc minimize [fmax] [max_steps] Minimize a structure with a NEP model 使用 NEP 模型优化结构 stable +calc -calc msd gpumdkit.sh -calc msd [max_corr_steps] Calculate MSD from trajectory 从轨迹计算 MSD stable +calc -calc nlist gpumdkit.sh -calc nlist [args...] Build neighbor lists 构建邻居列表 stable +calc -calc disp gpumdkit.sh -calc disp [args...] Calculate displacements 计算位移 stable +calc -calc avg-struct gpumdkit.sh -calc avg-struct [args...] Calculate averaged structure 计算平均结构 stable +calc -calc oct-tilt gpumdkit.sh -calc oct-tilt [args...] Calculate octahedral tilt 计算八面体倾斜 stable +calc -calc pol-abo3 gpumdkit.sh -calc pol-abo3 [args...] Calculate ABO3 local polarization 计算 ABO3 局域极化 stable +analyze -range gpumdkit.sh -range [hist] Analyze property ranges 分析性质范围 stable +analyze -analyze_comp gpumdkit.sh -analyze_comp Analyze structure composition 分析结构成分 stable +analyze -chem_species gpumdkit.sh -chem_species List chemical species 列出化学元素 stable +analyze -cbc gpumdkit.sh -cbc Check charge balance 检查电荷平衡 stable +analyze -min_dist gpumdkit.sh -min_dist Calculate minimum distance without PBC 计算无 PBC 最小距离 stable +analyze -min_dist_pbc gpumdkit.sh -min_dist_pbc Calculate minimum distance with PBC 计算带 PBC 最小距离 stable +analyze -filter_dist gpumdkit.sh -filter_dist Filter structures by minimum distance 按最小距离过滤结构 stable +analyze -filter_dist_pbc gpumdkit.sh -filter_dist_pbc Filter structures by minimum distance with PBC 按带 PBC 最小距离过滤结构 stable +analyze -filter_box gpumdkit.sh -filter_box Filter structures by box-edge limit 按盒子边长过滤结构 stable +analyze -filter_value gpumdkit.sh -filter_value Filter structures by property threshold 按性质阈值过滤结构 stable +analyze -filter_range gpumdkit.sh -filter_range Filter by element-pair distance range 按元素对距离范围过滤 stable +analyze -pda gpumdkit.sh -pda Calculate probability density 计算概率密度 stable +utility -time gpumdkit.sh -time Monitor GPUMD or NEP progress 监控 GPUMD 或 NEP 进度 stable +utility -nep_modifier gpumdkit.sh -nep_modifier Modify NEP model interactively 交互式修改 NEP 模型 stable diff --git a/docs/css/home.css b/docs/css/home.css index ec50fda..f6ea275 100644 --- a/docs/css/home.css +++ b/docs/css/home.css @@ -171,7 +171,7 @@ body { box-shadow: 0 20px 50px rgba(0,0,0,0.1); border: 1px solid rgba(0,0,0,0.05); overflow: hidden; - height: 650px; + height: 520px; display: flex; flex-direction: column; position: relative; diff --git a/docs/gallery.html b/docs/gallery.html index 932b19d..9f8a223 100644 --- a/docs/gallery.html +++ b/docs/gallery.html @@ -220,7 +220,7 @@