From 9d08999413908008a7f275b6bbc95ff56c1fc4f5 Mon Sep 17 00:00:00 2001 From: yanzihan Date: Sat, 6 Jun 2026 11:21:11 +0800 Subject: [PATCH 01/24] update --- src/f3_workflows.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/f3_workflows.sh b/src/f3_workflows.sh index 581668e..5794c27 100644 --- a/src/f3_workflows.sh +++ b/src/f3_workflows.sh @@ -39,7 +39,7 @@ echo " ---------------------------------------------------" # SCF batch pretreatment (main function) function f301_scf_batch_pretreatment(){ echo " +-------------------------------------------------------------+" - echo " | SCF BATCH PRETREATMENT TOOLS |" + echo " | SCF BATCH PRETREATMENT TOOLS |" echo " +-------------------------------------------------------------+" echo " | 1) VASP SCF batch pretreatment |" echo " | 2) CP2K SCF batch pretreatment |" From 906510e2b0fd0a800ecb70092225a8560ba9adf7 Mon Sep 17 00:00:00 2001 From: Xin Wu Date: Thu, 11 Jun 2026 22:57:49 +0900 Subject: [PATCH 02/24] Fix the bug in EMD-plot --- Scripts/plt_scripts/plt_emd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/plt_scripts/plt_emd.py b/Scripts/plt_scripts/plt_emd.py index 0514d11..2450ebe 100644 --- a/Scripts/plt_scripts/plt_emd.py +++ b/Scripts/plt_scripts/plt_emd.py @@ -59,7 +59,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])) @@ -67,7 +67,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: From c5665b904fffe59472588717394a40704f4f2f7a Mon Sep 17 00:00:00 2001 From: Xin Wu Date: Fri, 12 Jun 2026 11:10:46 +0900 Subject: [PATCH 03/24] Fix the bug in NEMD-plot without SHC --- Scripts/plt_scripts/plt_nemd.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Scripts/plt_scripts/plt_nemd.py b/Scripts/plt_scripts/plt_nemd.py index f40ea82..2a9aa37 100644 --- a/Scripts/plt_scripts/plt_nemd.py +++ b/Scripts/plt_scripts/plt_nemd.py @@ -35,7 +35,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): @@ -164,6 +164,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: @@ -210,6 +211,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 From e2ddddbcc5284f690b9ad116adf4c6784caaee69 Mon Sep 17 00:00:00 2001 From: ZihanYAN Date: Tue, 16 Jun 2026 21:12:51 +0800 Subject: [PATCH 04/24] fix: remove unnecessary chmod in update function to avoid git tracking permission changes --- Scripts/utils/update_gpumdkit.sh | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Scripts/utils/update_gpumdkit.sh b/Scripts/utils/update_gpumdkit.sh index da7e1ee..aefb60d 100644 --- a/Scripts/utils/update_gpumdkit.sh +++ b/Scripts/utils/update_gpumdkit.sh @@ -45,21 +45,10 @@ if [ "$local_commit" = "$remote_commit" ]; then 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 # 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 else echo "Error: Failed to pull code. Check Git configuration or network connection." exit 1 From 05488a3f9408a2889279aecd27d93929c28291d4 Mon Sep 17 00:00:00 2001 From: ZihanYAN Date: Tue, 16 Jun 2026 21:41:02 +0800 Subject: [PATCH 05/24] refactor: standardize argument checks and CLI usage in format_conversion scripts - Add sys.argv parameter validation to all Python scripts - Add dual usage hints (python xx.py / gpumdkit.sh -xx) - Convert xdatcar2exyz.py from argparse to sys.argv for consistency - Fix traj2exyz.py to exit on invalid arguments instead of continuing - All prompts and comments in English --- Scripts/format_conversion/abacus2xyz_scf.py | 1 + Scripts/format_conversion/add_groups.py | 6 +++++ Scripts/format_conversion/add_weight.py | 3 ++- Scripts/format_conversion/cif2exyz.py | 3 ++- Scripts/format_conversion/cif2pos.py | 3 ++- Scripts/format_conversion/clean_xyz.py | 6 +++++ Scripts/format_conversion/exyz2pos.py | 8 +++++- Scripts/format_conversion/get_frame.py | 6 +++++ Scripts/format_conversion/lmp2exyz.py | 3 ++- Scripts/format_conversion/mtp2xyz.py | 5 ++++ Scripts/format_conversion/out2exyz.py | 6 +++++ Scripts/format_conversion/pos2exyz.py | 5 ++-- Scripts/format_conversion/pos2lmp.py | 1 + Scripts/format_conversion/replicate.py | 6 +++-- Scripts/format_conversion/split_single_xyz.py | 2 +- Scripts/format_conversion/traj2exyz.py | 13 ++++----- Scripts/format_conversion/xdatcar2exyz.py | 27 +++++++++---------- 17 files changed, 73 insertions(+), 31 deletions(-) diff --git a/Scripts/format_conversion/abacus2xyz_scf.py b/Scripts/format_conversion/abacus2xyz_scf.py index 07b8051..906c495 100644 --- a/Scripts/format_conversion/abacus2xyz_scf.py +++ b/Scripts/format_conversion/abacus2xyz_scf.py @@ -26,6 +26,7 @@ def main(): if len(sys.argv) != 3: print("Usage: python abacus2xyz_scf.py ") + print(" or: gpumdkit.sh -abacus2xyz ") sys.exit(1) if __name__ == "__main__": main() diff --git a/Scripts/format_conversion/add_groups.py b/Scripts/format_conversion/add_groups.py index c0bcd2f..afbe12c 100644 --- a/Scripts/format_conversion/add_groups.py +++ b/Scripts/format_conversion/add_groups.py @@ -24,6 +24,12 @@ from ase.io import read, write import numpy as np +# Check arguments +if len(sys.argv) < 3: + print("Usage: python add_groups.py ...") + print(" or: gpumdkit.sh -addgroup ...") + sys.exit(1) + # Read the file name from command line arguments file_name = sys.argv[1] diff --git a/Scripts/format_conversion/add_weight.py b/Scripts/format_conversion/add_weight.py index ff3841b..4011e0f 100644 --- a/Scripts/format_conversion/add_weight.py +++ b/Scripts/format_conversion/add_weight.py @@ -28,7 +28,8 @@ def main(): # Check if the correct number of arguments are provided if len(sys.argv) != 4: - print("Usage: python script.py ") + print("Usage: python add_weight.py ") + print(" or: gpumdkit.sh -addweight ") sys.exit(1) # Parse command line arguments diff --git a/Scripts/format_conversion/cif2exyz.py b/Scripts/format_conversion/cif2exyz.py index 6b0ac7c..0f56b72 100644 --- a/Scripts/format_conversion/cif2exyz.py +++ b/Scripts/format_conversion/cif2exyz.py @@ -24,7 +24,8 @@ # Check command line arguments if len(sys.argv) != 3: - print(" Usage: python cif2exyz.py input.cif output.xyz") + print("Usage: python cif2exyz.py ") + print(" or: gpumdkit.sh -cif2exyz ") sys.exit(1) # Read input and output file paths diff --git a/Scripts/format_conversion/cif2pos.py b/Scripts/format_conversion/cif2pos.py index 8657fc6..8624acc 100644 --- a/Scripts/format_conversion/cif2pos.py +++ b/Scripts/format_conversion/cif2pos.py @@ -24,7 +24,8 @@ # Check command line arguments if len(sys.argv) != 3: - print(" Usage: python cif2poscar.py input.cif output.vasp") + print("Usage: python cif2pos.py ") + print(" or: gpumdkit.sh -cif2pos ") sys.exit(1) # Read input and output file paths diff --git a/Scripts/format_conversion/clean_xyz.py b/Scripts/format_conversion/clean_xyz.py index 2ae4e97..c9767d2 100644 --- a/Scripts/format_conversion/clean_xyz.py +++ b/Scripts/format_conversion/clean_xyz.py @@ -23,6 +23,12 @@ from ase.io import read, write import sys +# Check arguments +if len(sys.argv) < 3: + print("Usage: python clean_xyz.py ") + print(" or: gpumdkit.sh -clean_xyz ") + sys.exit(1) + # Read all frames from the input train.xyz file frames = read(sys.argv[1], index=':') diff --git a/Scripts/format_conversion/exyz2pos.py b/Scripts/format_conversion/exyz2pos.py index 092f680..3f1b19b 100644 --- a/Scripts/format_conversion/exyz2pos.py +++ b/Scripts/format_conversion/exyz2pos.py @@ -30,7 +30,13 @@ 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' +# Check arguments +if len(sys.argv) < 2: + print("Usage: python exyz2pos.py ") + print(" or: gpumdkit.sh -exyz2pos ") + sys.exit(1) + +input_file = sys.argv[1] # Read all frames frames = read(input_file, index=':') diff --git a/Scripts/format_conversion/get_frame.py b/Scripts/format_conversion/get_frame.py index 23e9971..10ead91 100644 --- a/Scripts/format_conversion/get_frame.py +++ b/Scripts/format_conversion/get_frame.py @@ -22,6 +22,12 @@ import sys from ase.io import read, write +# Check arguments +if len(sys.argv) < 3: + print("Usage: python get_frame.py ") + print(" or: gpumdkit.sh -get_frame ") + sys.exit(1) + def get_frame(): input_file = sys.argv[1] frame_number = int(sys.argv[2]) diff --git a/Scripts/format_conversion/lmp2exyz.py b/Scripts/format_conversion/lmp2exyz.py index 4533a91..08f9ad4 100644 --- a/Scripts/format_conversion/lmp2exyz.py +++ b/Scripts/format_conversion/lmp2exyz.py @@ -48,7 +48,8 @@ def lmp2exyz(dump_file, elements): if __name__ == '__main__': if len(sys.argv) < 3: - print(" Usage: python lmp2exyz.py ...") + print("Usage: python lmp2exyz.py ...") + print(" or: gpumdkit.sh -lmp2exyz ...") sys.exit(1) dump_file = sys.argv[1] diff --git a/Scripts/format_conversion/mtp2xyz.py b/Scripts/format_conversion/mtp2xyz.py index dd2d840..aca1e12 100644 --- a/Scripts/format_conversion/mtp2xyz.py +++ b/Scripts/format_conversion/mtp2xyz.py @@ -132,6 +132,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..c634115 100644 --- a/Scripts/format_conversion/out2exyz.py +++ b/Scripts/format_conversion/out2exyz.py @@ -23,6 +23,12 @@ from ase import Atoms, Atom from tqdm import tqdm +# Check arguments +if len(sys.argv) < 2: + print("Usage: python out2exyz.py ") + print(" or: gpumdkit.sh -out2exyz ") + sys.exit(1) + def Convert_atoms(atom): xx,yy,zz,yz,xz,xy = -atom.calc.results['stress']*atom.get_volume() atom.info['virial'] = np.array([(xx, xy, xz), (xy, yy, yz), (xz, yz, zz)]) diff --git a/Scripts/format_conversion/pos2exyz.py b/Scripts/format_conversion/pos2exyz.py index 8316016..211d450 100644 --- a/Scripts/format_conversion/pos2exyz.py +++ b/Scripts/format_conversion/pos2exyz.py @@ -44,9 +44,8 @@ def convert_poscar_to_extxyz(poscar_filenames, extxyz_filename): 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") + print("Usage: python pos2exyz.py ") + print(" or: gpumdkit.sh -pos2exyz ") sys.exit(1) poscar_filename_pattern = sys.argv[1] diff --git a/Scripts/format_conversion/pos2lmp.py b/Scripts/format_conversion/pos2lmp.py index b2cf10f..83122ae 100644 --- a/Scripts/format_conversion/pos2lmp.py +++ b/Scripts/format_conversion/pos2lmp.py @@ -30,6 +30,7 @@ def convert_poscar_to_lammps(poscar_path, lammps_data_path): if __name__ == "__main__": if len(sys.argv) != 3: print("Usage: python pos2lmp.py ") + print(" or: gpumdkit.sh -pos2lmp ") sys.exit(1) poscar_file = sys.argv[1] diff --git a/Scripts/format_conversion/replicate.py b/Scripts/format_conversion/replicate.py index 36a70f4..cb574ad 100644 --- a/Scripts/format_conversion/replicate.py +++ b/Scripts/format_conversion/replicate.py @@ -106,8 +106,10 @@ def reorder_atoms_by_input_species_order(atoms, original_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") + 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") + print(" or: gpumdkit.sh -replicate input.vasp output.vasp a b c") + print(" or: gpumdkit.sh -replicate input.vasp output.vasp target_num") sys.exit(1) infile = sys.argv[1] diff --git a/Scripts/format_conversion/split_single_xyz.py b/Scripts/format_conversion/split_single_xyz.py index 904cdb3..b862765 100644 --- a/Scripts/format_conversion/split_single_xyz.py +++ b/Scripts/format_conversion/split_single_xyz.py @@ -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..7466b7d 100644 --- a/Scripts/format_conversion/traj2exyz.py +++ b/Scripts/format_conversion/traj2exyz.py @@ -47,9 +47,10 @@ def convert_traj_to_extxyz(input_file, output_file): 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 + print("Usage: python traj2exyz.py ") + print(" or: gpumdkit.sh -traj2exyz ") + sys.exit(1) + + 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..e910238 100644 --- a/Scripts/format_conversion/xdatcar2exyz.py +++ b/Scripts/format_conversion/xdatcar2exyz.py @@ -19,39 +19,38 @@ ============================================================================= """ -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") +# Check arguments +if len(sys.argv) < 3: + print("Usage: python xdatcar2exyz.py ") + print(" or: gpumdkit.sh -xdat2exyz ") + sys.exit(1) -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}") From f61433d04112c8481f4e71a81ef3baa4afb980cd Mon Sep 17 00:00:00 2001 From: yanzihan Date: Wed, 17 Jun 2026 16:49:40 +0800 Subject: [PATCH 06/24] add -nep_modifier --- Scripts/utils/completion.sh | 2 +- Scripts/utils/nep_modifier/README.md | 298 ++++++++++++++++++ Scripts/utils/nep_modifier/README_zh-CN.md | 298 ++++++++++++++++++ Scripts/utils/nep_modifier/nep_modifier.py | 337 +++++++++++++++++++++ docs/updates.info | 7 +- gpumdkit.sh | 5 +- 6 files changed, 941 insertions(+), 6 deletions(-) create mode 100644 Scripts/utils/nep_modifier/README.md create mode 100644 Scripts/utils/nep_modifier/README_zh-CN.md create mode 100644 Scripts/utils/nep_modifier/nep_modifier.py diff --git a/Scripts/utils/completion.sh b/Scripts/utils/completion.sh index b1f8ff5..2f4b4e4 100644 --- a/Scripts/utils/completion.sh +++ b/Scripts/utils/completion.sh @@ -13,7 +13,7 @@ _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 -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 -nep_modifier" # Provide secondary completion based on the previous word case "$prev" in diff --git a/Scripts/utils/nep_modifier/README.md b/Scripts/utils/nep_modifier/README.md new file mode 100644 index 0000000..c3bcca7 --- /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, 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..e417d9a --- /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_tool.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, 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..469efbd --- /dev/null +++ b/Scripts/utils/nep_modifier/nep_modifier.py @@ -0,0 +1,337 @@ +""" +============================================================================= +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) +============================================================================= +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) + + +# ─── 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__": + main() diff --git a/docs/updates.info b/docs/updates.info index d218a66..4b02d14 100644 --- a/docs/updates.info +++ b/docs/updates.info @@ -1,13 +1,12 @@ # === User Configuration Section: Only modify these variables === -VERSION="1.5.5" -RELEASE_DATE="2026-05-18" +VERSION="1.5.6" +RELEASE_DATE="2026-06-17" HOME_PAGE="https://zhyan0603.github.io/GPUMDkit" CONTACT="yanzihan@westlake.edu.cn" # New features (one per line, in an array) NEW_FEATURES=( - "add -plt train_density" - "add -plt bec" + "add -nep_modifier" ) # Bug fixes (one per line, in an array) diff --git a/gpumdkit.sh b/gpumdkit.sh index 985bc53..0d5396a 100755 --- a/gpumdkit.sh +++ b/gpumdkit.sh @@ -19,7 +19,7 @@ if [ -z "$GPUMDkit_path" ]; then exit 1 fi -VERSION="1.5.5 (dev) (2026-05-16)" +VERSION="1.5.6 (dev) (2026-06-17)" plt_path="${GPUMDkit_path}/Scripts/plt_scripts" analyzer_path="${GPUMDkit_path}/Scripts/analyzer" @@ -669,6 +669,9 @@ if [ ! -z "$1" ]; then source ${GPUMDkit_path}/src/f2_sample_structures.sh parallel_pynep_sample_structures ;; + -nep_modifier) + source ${GPUMDkit_path}/Scripts/utils/nep_modifier/nep_modifier.py ;; + -frame_range) if [ ! -z "$2" ] && [ "$2" != "-h" ] && [ ! -z "$3" ] && [ ! -z "$4" ] ; then echo " Calling script by Zihan YAN " From e1a730508e48ef6d2f8469e6de7b4faaf848cbdd Mon Sep 17 00:00:00 2001 From: yanzihan Date: Wed, 17 Jun 2026 16:52:19 +0800 Subject: [PATCH 07/24] fix typo --- Scripts/utils/nep_modifier/README_zh-CN.md | 2 +- gpumdkit.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/utils/nep_modifier/README_zh-CN.md b/Scripts/utils/nep_modifier/README_zh-CN.md index e417d9a..317fda3 100644 --- a/Scripts/utils/nep_modifier/README_zh-CN.md +++ b/Scripts/utils/nep_modifier/README_zh-CN.md @@ -55,7 +55,7 @@ restart 文件为每个参数存储均值 `mu` 和标准差 `sigma`,分别代 2. 运行工具: ``` - python nep_tool.py + python nep_modifier.py ``` 3. 启动时工具会显示引用信息,然后提示输入文件。直接按 **Enter** 使用默认值(当前目录下的 `nep.txt nep.restart`): diff --git a/gpumdkit.sh b/gpumdkit.sh index 0d5396a..1100830 100755 --- a/gpumdkit.sh +++ b/gpumdkit.sh @@ -670,7 +670,7 @@ if [ ! -z "$1" ]; then parallel_pynep_sample_structures ;; -nep_modifier) - source ${GPUMDkit_path}/Scripts/utils/nep_modifier/nep_modifier.py ;; + python ${GPUMDkit_path}/Scripts/utils/nep_modifier/nep_modifier.py ;; -frame_range) if [ ! -z "$2" ] && [ "$2" != "-h" ] && [ ! -z "$3" ] && [ ! -z "$4" ] ; then From a0663e6c94c443aa3a1af61ccaf99fd316eb9a64 Mon Sep 17 00:00:00 2001 From: ZihanYAN Date: Sat, 20 Jun 2026 22:22:44 +0800 Subject: [PATCH 08/24] add skill and new tutorials --- .gitignore | 3 + docs/tutorials2/en/analyzers.md | 289 +++++++++++++++++++ docs/tutorials2/en/calculators.md | 312 +++++++++++++++++++++ docs/tutorials2/en/format_conversion.md | 273 ++++++++++++++++++ docs/tutorials2/en/index.md | 160 +++++++++++ docs/tutorials2/en/nep_training.md | 299 ++++++++++++++++++++ docs/tutorials2/en/quickstart.md | 244 ++++++++++++++++ docs/tutorials2/en/sampling.md | 221 +++++++++++++++ docs/tutorials2/en/visualization.md | 226 +++++++++++++++ docs/tutorials2/en/workflows.md | 280 ++++++++++++++++++ docs/tutorials2/zh/analyzers.md | 289 +++++++++++++++++++ docs/tutorials2/zh/calculators.md | 312 +++++++++++++++++++++ docs/tutorials2/zh/format_conversion.md | 273 ++++++++++++++++++ docs/tutorials2/zh/index.md | 160 +++++++++++ docs/tutorials2/zh/nep_training.md | 299 ++++++++++++++++++++ docs/tutorials2/zh/quickstart.md | 244 ++++++++++++++++ docs/tutorials2/zh/sampling.md | 221 +++++++++++++++ docs/tutorials2/zh/visualization.md | 226 +++++++++++++++ docs/tutorials2/zh/workflows.md | 280 ++++++++++++++++++ skills/README.md | 117 ++++++++ skills/gpumdkit-analyzers/SKILL.md | 235 ++++++++++++++++ skills/gpumdkit-calculators/SKILL.md | 241 ++++++++++++++++ skills/gpumdkit-format-conversion/SKILL.md | 173 ++++++++++++ skills/gpumdkit-main/SKILL.md | 153 ++++++++++ skills/gpumdkit-sampling/SKILL.md | 228 +++++++++++++++ skills/gpumdkit-visualization/SKILL.md | 216 ++++++++++++++ skills/gpumdkit-workflows/SKILL.md | 224 +++++++++++++++ 27 files changed, 6198 insertions(+) create mode 100644 docs/tutorials2/en/analyzers.md create mode 100644 docs/tutorials2/en/calculators.md create mode 100644 docs/tutorials2/en/format_conversion.md create mode 100644 docs/tutorials2/en/index.md create mode 100644 docs/tutorials2/en/nep_training.md create mode 100644 docs/tutorials2/en/quickstart.md create mode 100644 docs/tutorials2/en/sampling.md create mode 100644 docs/tutorials2/en/visualization.md create mode 100644 docs/tutorials2/en/workflows.md create mode 100644 docs/tutorials2/zh/analyzers.md create mode 100644 docs/tutorials2/zh/calculators.md create mode 100644 docs/tutorials2/zh/format_conversion.md create mode 100644 docs/tutorials2/zh/index.md create mode 100644 docs/tutorials2/zh/nep_training.md create mode 100644 docs/tutorials2/zh/quickstart.md create mode 100644 docs/tutorials2/zh/sampling.md create mode 100644 docs/tutorials2/zh/visualization.md create mode 100644 docs/tutorials2/zh/workflows.md create mode 100644 skills/README.md create mode 100644 skills/gpumdkit-analyzers/SKILL.md create mode 100644 skills/gpumdkit-calculators/SKILL.md create mode 100644 skills/gpumdkit-format-conversion/SKILL.md create mode 100644 skills/gpumdkit-main/SKILL.md create mode 100644 skills/gpumdkit-sampling/SKILL.md create mode 100644 skills/gpumdkit-visualization/SKILL.md create mode 100644 skills/gpumdkit-workflows/SKILL.md diff --git a/.gitignore b/.gitignore index e95b54f..4314cfc 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,9 @@ build/ .DS_Store Thumbs.db +# Opencode +.opencode + # Temporary / generated files *.log temp_*.xyz diff --git a/docs/tutorials2/en/analyzers.md b/docs/tutorials2/en/analyzers.md new file mode 100644 index 0000000..892f39a --- /dev/null +++ b/docs/tutorials2/en/analyzers.md @@ -0,0 +1,289 @@ +# Analyzers Guide + +
+

+ 中文 | English +

+
+ +This guide covers all analysis tools in GPUMDkit for structure validation, filtering, and quality control. + +## Available Tools + +| Tool | Command | Description | +|------|---------|-------------| +| Composition Analysis | `-analyze_comp` | Group structures by composition | +| Outlier Detection | Menu 502 | Find high-error structures | +| Chemical Species | Menu 503 | List unique elements | +| Charge Balance | `-cbc` | Check oxidation-state balance | +| Property Range | `-range` | Energy/force/virial statistics | +| Distance Filter | Menu 506 | Filter by minimum distance (no PBC) | +| Distance Filter (PBC) | Menu 506b | Filter by minimum distance (with PBC) | +| Minimum Distance | `-min_dist` | Calculate min distances (no PBC) | +| Minimum Distance (PBC) | `-min_dist_pbc` | Calculate min distances (with PBC) | +| Probability Density | Menu 508 | 3D diffusion channel analysis | + +## Interactive Mode + +```bash +gpumdkit.sh +# Select: 5) Analyzer +``` + +You'll see: + +``` ++------------------------------------------------------+ +| ANALYZER TOOLS | ++------------------------------------------------------+ +| 501) Analyze composition of extxyz | +| 502) Find outliers of extxyz | +| 503) Analyze chemical species of extxyz | +| 504) Check charge balance of extxyz | +| 505) Analyze energy/force/virial range | +| 506) Filter structures by minimum distance | +| 507) Get minimum interatomic distance | +| 508) Probability density analysis | ++------------------------------------------------------+ +``` + +## Command Reference + +### Composition Analysis + +Analyze and group structures by chemical composition. + +```bash +gpumdkit.sh -analyze_comp train.xyz +``` + +**Output:** Table of unique compositions with atom counts and structure counts. Interactive selection to export specific compositions. + +### Property Range Analysis + +Compute the range (min, max) of energy, force, or virial in an extxyz file. + +```bash +gpumdkit.sh -range [hist] + +# Examples +gpumdkit.sh -range train.xyz energy +gpumdkit.sh -range train.xyz force +gpumdkit.sh -range train.xyz virial +gpumdkit.sh -range train.xyz force hist # With histogram +``` + +**Output:** Min/max values. Optional histogram plot with `hist` argument. + +### Minimum Distance + +Calculate minimum interatomic distance for each element pair. + +```bash +# Fast calculation (no PBC) +gpumdkit.sh -min_dist dump.xyz + +# Accurate calculation (with PBC) +gpumdkit.sh -min_dist_pbc dump.xyz +``` + +**Output:** Table of minimum distances for all element pairs + +### Charge Balance Check + +Check oxidation-state balance for all structures. + +```bash +gpumdkit.sh -cbc train.xyz +``` + +**Output:** +- `balanced.xyz` - Charge-balanced structures +- `unbalanced.xyz` - Unbalanced structures +- `indices.txt` - Summary + +### Chemical Species Identification + +List all unique chemical elements in the file. + +```bash +# Interactive mode +gpumdkit.sh # Select: 5) Analyzer -> 503 +``` + +**Output:** Sorted list of all elements + +### Structure Filtering + +#### By Minimum Distance (No PBC) + +```bash +gpumdkit.sh # Select: 5) Analyzer -> 506 +``` + +**Input:** extxyz file, distance threshold +**Output:** `filtered_.xyz`, `filtered_out_.xyz` + +#### By Minimum Distance (With PBC) + +```bash +gpumdkit.sh # Select: 5) Analyzer -> 506b +``` + +More accurate for periodic systems. + +#### By Element-Pair Distance Range + +```bash +gpumdkit.sh -filter_range + +# Example: Filter Li-Li distances between 1.9 and 2.0 Å +gpumdkit.sh -filter_range dump.xyz Li Li 1.9 2.0 +``` + +**Output:** `filtered____.xyz` + +#### By Box Size + +```bash +gpumdkit.sh -filter_box + +# Example: Filter structures with box edge > 20 Å +gpumdkit.sh -filter_box dump.xyz 20 +``` + +**Output:** `filtered_by_box.xyz` + +#### By Property Value + +```bash +gpumdkit.sh -filter_value + +# Example: Keep structures with force < 20 eV/Å +gpumdkit.sh -filter_value train.xyz force 20 +``` + +**Output:** `filtered.xyz` + +### Outlier Detection + +Find outlier structures based on RMSE thresholds. + +```bash +gpumdkit.sh # Select: 5) Analyzer -> 502 +``` + +**Required files:** +- `train.xyz` +- `energy_train.out` +- `force_train.out` +- `stress_train.out` + +**Output:** `selected.xyz` (high-error), `remained.xyz` (low-error) + +### Probability Density Analysis + +Calculate 3D probability density of mobile ions from AIMD trajectory. + +```bash +gpumdkit.sh # Select: 5) Analyzer -> 508 +``` + +**Parameters:** +- Reference structure (POSCAR) +- Trajectory file (extxyz) +- Mobile species (e.g., Li) +- Grid interval (e.g., 0.25 Å) + +**Output:** `probability_density_.vasp` (CHGCAR format) + +## Common Workflows + +### Data Quality Check + +```bash +# 1. Check composition +gpumdkit.sh -analyze_comp train.xyz + +# 2. Check minimum distances +gpumdkit.sh -min_dist_pbc train.xyz + +# 3. Check force range +gpumdkit.sh -range train.xyz force + +# 4. Check for outliers +gpumdkit.sh # Select: 5) Analyzer -> 502 +``` + +### Structure Filtering Pipeline + +```bash +# 1. Filter by distance +gpumdkit.sh # Select: 5) Analyzer -> 506 + +# 2. Filter by box size +gpumdkit.sh -filter_box filtered.xyz 20 + +# 3. Filter by force value +gpumdkit.sh -filter_value filtered_by_box.xyz force 15 +``` + +### Diffusion Channel Analysis + +```bash +# 1. Calculate probability density +gpumdkit.sh # Select: 5) Analyzer -> 508 + +# 2. Visualize with VESTA or similar +# Open probability_density_0.25.vasp +``` + +## Additional Tools + +### Time Monitoring + +```bash +# Monitor GPUMD progress +gpumdkit.sh -time gpumd + +# Monitor NEP training progress +gpumdkit.sh -time nep +``` + +### Volume Analysis + +```bash +# Get average volume per temperature +python Scripts/analyzer/get_volume.py +# Requires: */K/thermo.out directories +``` + +## CLI Reference + +| Flag | Description | Syntax | +|------|-------------|--------| +| `-analyze_comp` | Composition analysis | `gpumdkit.sh -analyze_comp ` | +| `-range` | Property range | `gpumdkit.sh -range ` | +| `-min_dist` | Min distance (no PBC) | `gpumdkit.sh -min_dist ` | +| `-min_dist_pbc` | Min distance (PBC) | `gpumdkit.sh -min_dist_pbc ` | +| `-cbc` | Charge balance | `gpumdkit.sh -cbc ` | +| `-filter_range` | Filter by distance range | `gpumdkit.sh -filter_range ` | +| `-filter_box` | Filter by box size | `gpumdkit.sh -filter_box ` | +| `-filter_value` | Filter by property | `gpumdkit.sh -filter_value ` | +| `-time` | Time monitoring | `gpumdkit.sh -time ` | + +## Dependencies + +| Tool | Required Packages | +|------|------------------| +| All Python scripts | `ase`, `numpy` | +| Distance calculations | `scipy` | +| Charge balance | `pymatgen`, `tqdm` | +| Property range | `matplotlib` | +| Probability density | `pymatgen` | + +## See Also + +- [Format Conversion](format_conversion.md) - Convert file formats +- [Calculators](calculators.md) - Compute properties +- [Visualization](visualization.md) - Plot results diff --git a/docs/tutorials2/en/calculators.md b/docs/tutorials2/en/calculators.md new file mode 100644 index 0000000..57a9112 --- /dev/null +++ b/docs/tutorials2/en/calculators.md @@ -0,0 +1,312 @@ +# Calculators Guide + +
+

+ 中文 | English +

+
+ +This guide covers all calculator tools in GPUMDkit for computing material properties. + +## Available Calculators + +| Calculator | Command | Description | +|------------|---------|-------------| +| Ionic Conductivity | `-calc ionic-cond` | Calculate ionic conductivity from MSD | +| NEP Properties | `-calc nep` | Compute energy/force/stress with NEP | +| Descriptors | `-calc des` | Calculate NEP descriptors for analysis | +| DOAS | `-calc doas` | Density of atomistic states | +| NEB | Direct Python | Nudged elastic band calculation | +| Neighbor List | `-calc nlist` | Build neighbor lists for analysis | +| Displacement | `-calc disp` | Calculate atomic displacements | +| Averaged Structure | `-calc avg-struct` | Time-averaged structure from trajectory | +| Octahedral Tilt | `-calc oct-tilt` | Perovskite octahedral tilt angles | +| Polarization | `-calc pol-abo3` | ABO3 local polarization | +| Minimization | `-calc minimize` | Structure relaxation with NEP | +| MSD | `-calc msd` | Mean square displacement from trajectory | + +## Interactive Mode + +```bash +gpumdkit.sh +# Select: 4) Calculators +``` + +You'll see: + +``` ++----------------------------------------------------------+ +| CALCULATOR TOOLS | ++----------------------------------------------------------+ +| 401) Calc ionic conductivity | +| 402) Calc properties by nep | +| 403) Calc descriptors of specific elements | +| 404) Calc density of atomistic states (DOAS) | +| 405) Calc nudged elastic band (NEB) by nep | +| 406) Build neighbor list | +| 407) Calc displacement from trajectory | +| 408) Calc averaged structure | +| 409) Calc octahedral tilt | +| 410) Calc polarization for ABO3 | +| 411) Minimize structure by nep | +| 412) Calc mean square displacement (MSD) from trajectory | ++----------------------------------------------------------+ +``` + +## Command Reference + +### Ionic Conductivity + +Calculate ionic conductivity from MSD data using the Nernst-Einstein equation. + +```bash +gpumdkit.sh -calc ionic-cond + +# Examples +gpumdkit.sh -calc ionic-cond Li 1 # Lithium ion (Li+) +gpumdkit.sh -calc ionic-cond Na 1 # Sodium ion (Na+) +gpumdkit.sh -calc ionic-cond O -2 # Oxygen ion (O2-) +``` + +**Required files in current directory:** +- `msd.out` - From GPUMD `compute_msd` +- `thermo.out` - For temperature +- `model.xyz` - For volume +- `run.in` - For simulation parameters + +**Output:** Ionic diffusivity and conductivity values + +### NEP Property Prediction + +Calculate energies, forces, and stresses using a NEP model as a DFT surrogate. + +```bash +gpumdkit.sh -calc nep + +# Example +gpumdkit.sh -calc nep structures.xyz predictions.xyz nep.txt +``` + +**Note:** Clean input with `gpumdkit.sh -clean_xyz` first to remove existing properties. + +### Descriptors + +Calculate NEP descriptors for dimensionality reduction and structure analysis. + +```bash +gpumdkit.sh -calc des + +# Example +gpumdkit.sh -calc des train.xyz descriptors.npy nep.txt Li +``` + +**Visualize with:** +```bash +gpumdkit.sh -plt des pca # PCA visualization +gpumdkit.sh -plt des umap # UMAP visualization +``` + +### Density of Atomistic States (DOAS) + +Calculate per-atom energy distributions grouped by element type. + +```bash +gpumdkit.sh -calc doas + +# Example +gpumdkit.sh -calc doas structures.xyz nep.txt doas.out +``` + +**Visualize with:** +```bash +gpumdkit.sh -plt doas doas.out Li +``` + +### Mean Square Displacement (MSD) + +Calculate directional MSD from an extxyz trajectory. + +```bash +gpumdkit.sh -calc msd [max_corr_steps] + +# Example: Li with 10 fs timestep +gpumdkit.sh -calc msd dump.xyz Li 10 +``` + +**Output:** `msd.out` (Time/ps, MSD_x, MSD_y, MSD_z) + +### Neighbor List + +Build neighbor lists for perovskite analysis. + +```bash +gpumdkit.sh -calc nlist -i -c -n -C -E + +# Examples +gpumdkit.sh -calc nlist -i model.xyz -c 4 -n 12 -C Ti -E O +gpumdkit.sh -calc nlist -i model.xyz -c 4 -n 12 -C Pb Sr -E O +``` + +**Output:** `nl-
-.dat` + +### Displacement + +Calculate atomic displacements from trajectory using neighbor list. + +```bash +gpumdkit.sh -calc disp -i -n -o + +# Example +gpumdkit.sh -calc disp -i movie.xyz -n nl-Pb-O.dat -o displacements.dat +``` + +**Optional frame slicing:** `-s -t -p -l ` + +### Averaged Structure + +Generate time-averaged structure from trajectory. + +```bash +gpumdkit.sh -calc avg-struct -i -l -o + +# Example: Average last 20% of frames +gpumdkit.sh -calc avg-struct -i movie.xyz -l 0.2 -o averaged.xyz +``` + +### Octahedral Tilt + +Calculate octahedral tilt angles for perovskite systems. + +```bash +gpumdkit.sh -calc oct-tilt -i -n -o + +# Example +gpumdkit.sh -calc oct-tilt -i model.xyz -n nl-Ti-O.dat -o octahedral_tilt.dat +``` + +### Polarization (ABO3) + +Calculate local polarization for ABO3 perovskites. + +```bash +gpumdkit.sh -calc pol-abo3 -i \ + --nl-ba \ + --nl-bo \ + --bec + +# Example +gpumdkit.sh -calc pol-abo3 -i model.xyz \ + --nl-ba nl-Ti-Pb.dat \ + --nl-bo nl-Ti-O.dat \ + --bec Pb=2.5 Sr=2.0 Ti=4.0 O=-2.0 +``` + +### Structure Minimization + +Relax structures using BFGS optimizer with NEP model. + +```bash +gpumdkit.sh -calc minimize [fmax] [max_steps] + +# Example +gpumdkit.sh -calc minimize POSCAR nep.txt 0.01 1000 +``` + +**Parameters:** +- `fmax`: Force convergence threshold (default: 0.01 eV/Å) +- `max_steps`: Maximum optimization steps (default: 1000) + +**Output:** `minimize.xyz` (optimization trajectory) + +### NEB Calculation + +Perform nudged elastic band calculations for migration barriers. + +```bash +# Direct Python execution +python Scripts/calculators/neb_calculation.py + +# Example +python Scripts/calculators/neb_calculation.py init.xyz fin.xyz 9 nep.txt +``` + +## Common Workflows + +### Ionic Transport Analysis + +```bash +# 1. Run MD with compute_msd in run.in +# 2. Calculate MSD +gpumdkit.sh -calc msd dump.xyz Li 10 + +# 3. Calculate conductivity +gpumdkit.sh -calc ionic-cond Li 1 + +# 4. Visualize +gpumdkit.sh -plt msd +gpumdkit.sh -plt sdc +``` + +### Descriptor Analysis + +```bash +# 1. Calculate descriptors +gpumdkit.sh -calc des train.xyz descriptors.npy nep.txt Li + +# 2. Visualize with PCA +gpumdkit.sh -plt des pca + +# 3. Or visualize with UMAP +gpumdkit.sh -plt des umap +``` + +### Perovskite Analysis + +```bash +# 1. Build neighbor lists +gpumdkit.sh -calc nlist -i model.xyz -c 4 -n 12 -C Ti -E O +gpumdkit.sh -calc nlist -i model.xyz -c 4 -n 12 -C Ti -E Pb + +# 2. Calculate displacements +gpumdkit.sh -calc disp -i movie.xyz -n nl-Ti-O.dat -o disp.dat + +# 3. Calculate tilt +gpumdkit.sh -calc oct-tilt -i movie.xyz -n nl-Ti-O.dat -o tilt.dat + +# 4. Calculate polarization +gpumdkit.sh -calc pol-abo3 -i movie.xyz \ + --nl-ba nl-Ti-Pb.dat --nl-bo nl-Ti-O.dat \ + --bec Pb=2.5 Ti=4.0 O=-2.0 +``` + +### Structure Relaxation + +```bash +# 1. Minimize structure +gpumdkit.sh -calc minimize POSCAR nep.txt 0.01 1000 + +# 2. Use minimized structure for MD +cp minimize.xyz relaxed_model.xyz +``` + +## Dependencies + +| Calculator | Required Packages | +|------------|------------------| +| All | `numpy`, `ase` | +| ionic-cond | `scipy` | +| nep, des, doas, minimize | `calorine` | +| nlist, disp, oct-tilt, pol-abo3 | `ferrodispcalc` | +| neb | `calorine`, `matplotlib` | + +Install dependencies: +```bash +pip install numpy ase scipy calorine matplotlib tqdm +pip3 install git+https://github.com/MoseyQAQ/ferrodispcalc.git +``` + +## See Also + +- [Visualization](visualization.md) - Plot calculation results +- [Analyzers](analyzers.md) - Structure analysis +- [NEP Training Guide](nep_training.md) - Complete training workflow diff --git a/docs/tutorials2/en/format_conversion.md b/docs/tutorials2/en/format_conversion.md new file mode 100644 index 0000000..f4109bd --- /dev/null +++ b/docs/tutorials2/en/format_conversion.md @@ -0,0 +1,273 @@ +# Format Conversion Guide + +
+

+ 中文 | English +

+
+ +This guide covers all format conversion tools in GPUMDkit. + +## Supported Formats + +| Format | Extensions | Description | +|--------|-----------|-------------| +| VASP | POSCAR, OUTCAR, XDATCAR, vasprun.xml | Vienna Ab initio Simulation Package | +| LAMMPS | .data, dump.* | Large-scale Atomic/Molecular Massively Parallel Simulator | +| CP2K | .log, pos.xyz, frc.xyz, cell.cell | Quantum chemistry and solid state physics | +| ABACUS | running_scf.log, running_md.log | Atomic-orbital Based Ab-initio Computation | +| CIF | .cif | Crystallographic Information File | +| MTP | .cfg | Moment Tensor Potential format | +| ASE | .traj | Atomic Simulation Environment trajectory | +| extxyz | .xyz | Extended XYZ (primary working format) | + +## Interactive Mode + +Launch the interactive menu and select option 1: + +```bash +gpumdkit.sh +# Select: 1) Format Conversion +``` + +You'll see: + +``` ++-------------------------------------------------------------+ +| FORMAT CONVERSION TOOLS | ++-------------------------------------------------------------+ +| 101) VASP to extxyz 106) Add group labels | +| 102) MTP to extxyz 107) Add weight to extxyz | +| 103) CP2K to extxyz 108) Extract frame extxyz | +| 104) ABACUS to extxyz 109) Clean XYZ info | +| 105) extxyz to POSCAR 110) Replicate structure | ++-------------------------------------------------------------+ +| out2exyz) OUTCAR to extxyz xdat2exyz) XDATCAR to extxyz | +| pos2exyz) POSCAR to extxyz pos2lmp) POSCAR to LAMMPS | +| cif2pos) CIF to POSCAR lmp2exyz) LAMMPS to extxyz | +| cif2exyz) CIF to extxyz traj2exyz) ASE traj to extxyz| ++-------------------------------------------------------------+ +| 000) Return to main menu | ++-------------------------------------------------------------+ +``` + +## Command-Line Mode + +### VASP Conversions + +#### OUTCAR to extxyz + +```bash +# Shell version (supports both OUTCAR and vasprun.xml) +gpumdkit.sh -out2xyz + +# Python version (OUTCAR only) +gpumdkit.sh -out2exyz + +# Example +gpumdkit.sh -out2xyz ./vasp_results/ +``` + +#### XDATCAR to extxyz + +```bash +gpumdkit.sh -xdat2exyz XDATCAR output.xyz +``` + +#### POSCAR to extxyz + +```bash +gpumdkit.sh -pos2exyz POSCAR model.xyz +``` + +#### extxyz to POSCAR + +```bash +# Converts ALL frames to separate POSCAR files +gpumdkit.sh -exyz2pos structures.xyz +``` + +### LAMMPS Conversions + +#### LAMMPS dump to extxyz + +```bash +# IMPORTANT: Element symbols must match atom type IDs in dump file +gpumdkit.sh -lmp2exyz dump.lammpstrj Li Y Cl + +# Example +gpumdkit.sh -lmp2exyz trajectory.dump Na Cl +``` + +#### POSCAR to LAMMPS data + +```bash +gpumdkit.sh -pos2lmp POSCAR lammps.data +``` + +### CIF Conversions + +```bash +# CIF to POSCAR +gpumdkit.sh -cif2pos input.cif POSCAR.vasp + +# CIF to extxyz +gpumdkit.sh -cif2exyz input.cif model.xyz +``` + +### Other Conversions + +```bash +# ASE trajectory to extxyz +gpumdkit.sh -traj2exyz input.traj output.xyz +``` + +## Structure Manipulation + +### Add Group Labels + +Group labels are required for GPUMD/NEP to identify atom types: + +```bash +gpumdkit.sh -addgroup POSCAR ... + +# Example +gpumdkit.sh -addgroup POSCAR Li Y Cl +``` + +This creates `model.xyz` with group labels assigned to each atom. + +### Add Weights + +Add weight labels to structures for weighted training: + +```bash +gpumdkit.sh -addweight input.xyz output.xyz + +# Example +gpumdkit.sh -addweight train.xyz weighted.xyz 2.0 +``` + +### Replicate Structure + +Create supercells from unit cells: + +```bash +# By replication factors +gpumdkit.sh -replicate POSCAR supercell.vasp 2 2 2 + +# By target atom count +gpumdkit.sh -replicate POSCAR supercell.vasp 256 +``` + +### Extract Frame + +Extract a specific frame from a trajectory: + +```bash +# 0-based index +gpumdkit.sh -get_frame trajectory.xyz 1000 +``` + +### Clean XYZ Metadata + +Remove extra metadata from extxyz files: + +```bash +gpumdkit.sh -clean_xyz input.xyz clean.xyz +``` + +## Complete CLI Reference + +| Flag | Description | Syntax | +|------|-------------|--------| +| `-out2xyz` | OUTCAR to extxyz (shell) | `gpumdkit.sh -out2xyz ` | +| `-out2exyz` | OUTCAR to extxyz (python) | `gpumdkit.sh -out2exyz ` | +| `-pos2exyz` | POSCAR to extxyz | `gpumdkit.sh -pos2exyz ` | +| `-exyz2pos` | extxyz to POSCAR | `gpumdkit.sh -exyz2pos ` | +| `-pos2lmp` | POSCAR to LAMMPS data | `gpumdkit.sh -pos2lmp ` | +| `-lmp2exyz` | LAMMPS dump to extxyz | `gpumdkit.sh -lmp2exyz ` | +| `-cif2pos` | CIF to POSCAR | `gpumdkit.sh -cif2pos ` | +| `-cif2exyz` | CIF to extxyz | `gpumdkit.sh -cif2exyz ` | +| `-xdat2exyz` | XDATCAR to extxyz | `gpumdkit.sh -xdat2exyz XDATCAR dump.xyz` | +| `-traj2exyz` | ASE traj to extxyz | `gpumdkit.sh -traj2exyz ` | +| `-addgroup` | Add group labels | `gpumdkit.sh -addgroup ` | +| `-addweight` | Add weight | `gpumdkit.sh -addweight ` | +| `-replicate` | Replicate structure | `gpumdkit.sh -replicate a b c` | +| `-get_frame` | Extract frame | `gpumdkit.sh -get_frame ` | +| `-clean_xyz` | Clean extxyz info | `gpumdkit.sh -clean_xyz ` | + +## Examples + +### Example 1: Convert VASP MD Output + +```bash +# Convert all OUTCAR files in current directory +gpumdkit.sh -out2xyz . + +# Add group labels for NEP training +gpumdkit.sh -addgroup POSCAR Pb Ti O + +# Result: model.xyz ready for NEP training +``` + +### Example 2: Prepare LAMMPS Simulation + +```bash +# Convert POSCAR to LAMMPS data +gpumdkit.sh -pos2lmp POSCAR system.data + +# After LAMMPS simulation, convert dump back +gpumdkit.sh -lmp2exyz dump.lammpstrj Li P S +``` + +### Example 3: Batch Conversion + +```bash +# Convert multiple OUTCAR files +for dir in run_*; do + gpumdkit.sh -out2xyz "$dir" + mv "$dir"/model.xyz "$dir"/trajectory.xyz +done +``` + +### Example 4: Structure Replication + +```bash +# Create 2x2x2 supercell +gpumdkit.sh -replicate POSCAR supercell_222.vasp 2 2 2 + +# Create supercell with ~256 atoms +gpumdkit.sh -replicate POSCAR supercell_256.vasp 256 +``` + +## Important Notes + +1. **extxyz is the primary format**: Most GPUMDkit tools work with extxyz files +2. **Group labels are essential**: Required for GPUMD/NEP to identify atom types +3. **Frame indexing is 0-based**: First frame is index 0 +4. **Element ordering matters for LAMMPS**: Must match atom type IDs in dump file +5. **exyz2pos exports all frames**: Creates separate POSCAR for each frame + +## Dependencies + +Most Python scripts require: +- `ase` (Atomic Simulation Environment) +- `numpy` + +## Troubleshooting + +### Issue: Missing element information +**Solution**: Ensure POSCAR has correct element names in the header + +### Issue: Incorrect atom count +**Solution**: Check if POSCAR has selective dynamics enabled + +### Issue: LAMMPS conversion wrong species +**Solution**: Verify element order matches atom type IDs in dump file + +## See Also + +- [Calculators](calculators.md) - Compute material properties +- [Analyzers](analyzers.md) - Structure analysis +- [NEP Training Guide](nep_training.md) - Complete training workflow diff --git a/docs/tutorials2/en/index.md b/docs/tutorials2/en/index.md new file mode 100644 index 0000000..079eec7 --- /dev/null +++ b/docs/tutorials2/en/index.md @@ -0,0 +1,160 @@ +# GPUMDkit Tutorials + +
+

+ 中文 | English +

+
+ +Welcome to **GPUMDkit** - a powerful command-line toolkit for GPUMD and NEP! + +## What is GPUMDkit? + +GPUMDkit streamlines your molecular dynamics workflow with: + +- **Format Conversion**: Convert between VASP, LAMMPS, CP2K, ABACUS, CIF, and extxyz formats +- **Calculators**: Compute ionic conductivity, descriptors, MSD, NEB, and more +- **Analyzers**: Structure validation, filtering, composition analysis +- **Visualization**: 31+ plot types for training, transport, and structural analysis +- **Workflows**: Batch processing for DFT and MD simulations +- **Sampling**: Structure selection using uniform, random, or FPS methods + +## Quick Start + +### Installation + +```bash +# Clone the repository +git clone https://github.com/zhyan0603/GPUMDkit.git + +# Install +cd GPUMDkit +source ./install.sh +``` + +### Dependencies + +```bash +# Create conda environment +conda create -n gpumdkit python=3.12 +conda activate gpumdkit + +# Install required packages +pip install neptrain ase pymatgen dpdata numpy scipy matplotlib +``` + +### Basic Usage + +```bash +# Interactive mode (menu-driven) +gpumdkit.sh + +# Command-line mode +gpumdkit.sh -