pymdkit 1.3.0__tar.gz → 1.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pymdkit-1.3.0/src/pymdkit.egg-info → pymdkit-1.4.0}/PKG-INFO +82 -64
- pymdkit-1.4.0/README.md +241 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/pyproject.toml +7 -5
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/__init__.py +1 -1
- pymdkit-1.4.0/src/pymdkit/commands/_extxyz.py +36 -0
- pymdkit-1.4.0/src/pymdkit/commands/_reduction.py +99 -0
- pymdkit-1.3.0/src/pymdkit/commands/stable_entry.py → pymdkit-1.4.0/src/pymdkit/commands/chemsys_entry.py +2 -2
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/compute_msd_all_groups.py +2 -2
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/compute_rmsd.py +3 -3
- pymdkit-1.4.0/src/pymdkit/commands/convert.py +160 -0
- pymdkit-1.3.0/src/pymdkit/commands/electrostatic_energy.py → pymdkit-1.4.0/src/pymdkit/commands/ewald.py +3 -3
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/gather_contcar.py +1 -1
- pymdkit-1.3.0/src/pymdkit/commands/add_groups.py → pymdkit-1.4.0/src/pymdkit/commands/gpumd_group.py +1 -1
- pymdkit-1.4.0/src/pymdkit/commands/gpumd_thermo.py +250 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/nep_rmse.py +28 -33
- pymdkit-1.4.0/src/pymdkit/commands/pca.py +39 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/substitute.py +4 -4
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/symmetrize.py +2 -2
- pymdkit-1.4.0/src/pymdkit/commands/trj_extract.py +99 -0
- pymdkit-1.4.0/src/pymdkit/commands/umap.py +38 -0
- pymdkit-1.3.0/src/pymdkit/commands/final_energy.py → pymdkit-1.4.0/src/pymdkit/commands/vasp_fe.py +1 -1
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/pymdkit_main.py +6 -6
- {pymdkit-1.3.0 → pymdkit-1.4.0/src/pymdkit.egg-info}/PKG-INFO +82 -64
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit.egg-info/SOURCES.txt +11 -5
- pymdkit-1.4.0/src/pymdkit.egg-info/entry_points.txt +2 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit.egg-info/requires.txt +2 -0
- pymdkit-1.3.0/README.md +0 -225
- pymdkit-1.3.0/src/pymdkit/commands/stru2xyz.py +0 -100
- pymdkit-1.3.0/src/pymdkit.egg-info/entry_points.txt +0 -2
- {pymdkit-1.3.0 → pymdkit-1.4.0}/LICENSE +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/setup.cfg +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/__init__.py +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/_fileio.py +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/_vasp_output.py +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/_vaspset.py +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/compute_ehull.py +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/perturb.py +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/submit_vasp.py +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/supercell.py +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/vasp2xyz.py +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/vasp_relax.py +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit/commands/vasp_static.py +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit.egg-info/dependency_links.txt +0 -0
- {pymdkit-1.3.0 → pymdkit-1.4.0}/src/pymdkit.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pymdkit
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: A unified command-line toolkit for atomistic / MD structure workflows.
|
|
5
5
|
Author-email: Yueda Wang <ydwang0608@ustc.edu.cn>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -20,14 +20,16 @@ Requires-Dist: mp-api
|
|
|
20
20
|
Requires-Dist: py4vasp-core
|
|
21
21
|
Requires-Dist: pyxtal
|
|
22
22
|
Requires-Dist: dpdata
|
|
23
|
+
Requires-Dist: matplotlib
|
|
24
|
+
Requires-Dist: umap-learn
|
|
23
25
|
Dynamic: license-file
|
|
24
26
|
|
|
25
27
|
# pymdkit
|
|
26
28
|
|
|
27
29
|
A single command-line tool that bundles a collection of atomistic / molecular-dynamics
|
|
28
|
-
structure scripts behind one executable: `
|
|
30
|
+
structure scripts behind one executable: `pmk`. Instead of copying individual
|
|
29
31
|
scripts into each working folder and running `python some_script.py`, you install
|
|
30
|
-
`pymdkit` once and call any tool from anywhere as `
|
|
32
|
+
`pymdkit` once and call any tool from anywhere as `pmk <command> [options]`.
|
|
31
33
|
|
|
32
34
|
Every command exposes named `-flags` (no positional guessing), and each underlying
|
|
33
35
|
script is still runnable on its own.
|
|
@@ -42,15 +44,15 @@ conda activate pymdkit
|
|
|
42
44
|
pip install pymdkit
|
|
43
45
|
```
|
|
44
46
|
|
|
45
|
-
This installs the `
|
|
46
|
-
with its direct dependencies
|
|
47
|
+
This installs the `pmk` command into the active conda environment, together
|
|
48
|
+
with its direct dependencies, including ASE, pymatgen, py4vasp-core, dpdata, matplotlib, and UMAP. Some of these packages may install their own transitive dependencies.
|
|
47
49
|
|
|
48
50
|
Verify:
|
|
49
51
|
|
|
50
52
|
```bash
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
pmk -version
|
|
54
|
+
pmk -help # lists every command
|
|
55
|
+
pmk <command> -help # shows that command's flags
|
|
54
56
|
```
|
|
55
57
|
|
|
56
58
|
## Commands
|
|
@@ -61,19 +63,23 @@ directory for job sub-folders automatically.
|
|
|
61
63
|
|
|
62
64
|
| Command | What it does |
|
|
63
65
|
|---|---|
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
+
| `gpumd-group` | Tag atoms with a GPUMD group index by element order |
|
|
67
|
+
| `ewald` | Compute CIF electrostatic energy with pymatgen EwaldSummation |
|
|
66
68
|
| `ehull` | Auto-detect VASP job folders and compute E_hull vs Materials Project |
|
|
67
|
-
| `
|
|
69
|
+
| `vasp-fe` | List VASP job final energies from lowest to highest |
|
|
68
70
|
| `gather-contcar` | Collect CONTCARs from VASP job folders into one folder, renamed `<folder>.vasp` |
|
|
71
|
+
| `gpumd-thermo` | Export and plot GPUMD thermo data and detect sustained equilibrium changes |
|
|
72
|
+
| `pca` | Reduce descriptor data to two dimensions; optional FPS sampling |
|
|
73
|
+
| `trj-extract` | Extract a GPUMD XYZ trajectory by time range |
|
|
74
|
+
| `umap` | Reduce descriptor data to two dimensions with UMAP; optional FPS sampling |
|
|
69
75
|
| `msd` | Diffusivity & conductivity from GPUMD MSD jobs (auto-scans `<structure>/<temp>/`) |
|
|
70
76
|
| `nep-rmse` | Compute NEP energy/force/stress RMSE with terminal plots and optional candidate selection |
|
|
71
77
|
| `perturb` | Generate perturbed structures with dpdata |
|
|
72
78
|
| `vasp2xyz` | Collect SCF-converged VASP job folders (any name) into one extxyz file |
|
|
73
79
|
| `submit-vasp` | Submit/resubmit VASP job folders while limiting active queue jobs |
|
|
74
80
|
| `rmsd` | Compute RMSD between two structure files, or all pairs in a folder |
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
81
|
+
| `chemsys-entry` | Download stable Materials Project structures for a chemical system |
|
|
82
|
+
| `convert` | Convert structures, trajectories, or folders between ASE/pymatgen formats |
|
|
77
83
|
| `substitute` | Randomly substitute or remove selected atoms/sites from a structure |
|
|
78
84
|
| `supercell` | Build a supercell with cell lengths capped at a maximum (Angstrom); optional per-temperature GPUMD setup |
|
|
79
85
|
| `symmetrize` | Import space-group symmetry into a structure file (or folder) -> CIF |
|
|
@@ -83,47 +89,53 @@ directory for job sub-folders automatically.
|
|
|
83
89
|
## Examples
|
|
84
90
|
|
|
85
91
|
```bash
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
pmk gpumd-group -i opted.cif -elements Li Y Cl -o model.xyz
|
|
93
|
+
pmk gpumd-group -if cifs/ -elements Li Y Cl -of cifs-grouped/ # whole folder
|
|
94
|
+
pmk gpumd-group -elements Li Y Cl # scan subfolders, tag each model.xyz in place
|
|
95
|
+
pmk convert -i opted.vasp -o opted.xyz # convert one structure
|
|
96
|
+
pmk convert -if vasp-opted -of cif-opted -oe cif # folder conversion target format
|
|
97
|
+
pmk convert -it train.xyz -ot train.extxyz # convert a complete trajectory
|
|
98
|
+
pmk supercell -i opted.vasp -o sc.vasp -max-abc 20 # cell lengths <= 20 A
|
|
99
|
+
pmk supercell -if vasp-opted -max-abc 20 -individual # per-structure ./<name>/<name>.<ext>
|
|
100
|
+
pmk supercell -if extxyz-opted -max-abc 24 -individual -temp 500 600 -md-if input-files -add-groups Li Y Cl
|
|
95
101
|
# GPUMD: ./<name>/model.xyz (grouped) + ./<name>/<T>/ jobs
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
nohup
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
102
|
+
pmk vasp-relax -i opted.vasp # relax inputs in current dir
|
|
103
|
+
pmk vasp-relax -if optimal_occupancy # one ./<name>/ job folder per structure
|
|
104
|
+
pmk vasp-static -if cifs/ -custom-setting my_incar.txt # static inputs, custom INCAR
|
|
105
|
+
pmk vasp-static -it traj.xyz # one ./frame_N/ job per trajectory frame
|
|
106
|
+
pmk msd # scans <structure>/<temp>/ -> per-job msd/ + msd_summary.txt
|
|
107
|
+
pmk msd -diffuse_ion Li -ion_charge 1 # choose the mobile ion for conductivity
|
|
108
|
+
pmk chemsys-entry -s Li La Ta Cl # MP stable entries -> Li-La-Ta-Cl-stable-entries/
|
|
109
|
+
pmk ehull -mp-api-key $MP_API_KEY # scans ./ for VASP jobs -> ehull.txt
|
|
110
|
+
pmk ehull -local Li-La-Ta-Cl-stable-entries-opted
|
|
111
|
+
pmk vasp-fe # scans ./ for VASP jobs -> final-energy.txt with convergence status
|
|
112
|
+
pmk gather-contcar -of vasp-opted # CONTCARs -> vasp-opted/<folder>.vasp
|
|
113
|
+
pmk gather-contcar -of vasp-opted -ehull 0.028 # only structures with E_hull < 0.028 eV/atom
|
|
114
|
+
pmk vasp2xyz # scans ./ for VASP output folders -> scf-converged.xyz
|
|
115
|
+
pmk vasp2xyz -position-only # write positions only, without energy/forces/stress
|
|
116
|
+
pmk submit-vasp -subscript sub_vasp -queue slurm -max-job-num 30
|
|
117
|
+
nohup pmk submit-vasp -subscript sub_vasp -queue slurm -max-job-num 30 > submit-vasp.log 2>&1 &
|
|
118
|
+
pmk substitute -i Li3YCl6.cif -se Li -sn 3 -we Na -wn 3 -on 100
|
|
119
|
+
pmk substitute -i Li3YCl6.cif -se Li -sn 3 -we none -on 100
|
|
120
|
+
pmk substitute -i Li96Ta6La11Cl72.cif -se Li1 Li2 -sn 20 67 -we none -on 100
|
|
121
|
+
pmk substitute -i Li96Ta6La11Cl72.cif -se Li2 -we none -ref La Ta -d 1.01 1.02
|
|
122
|
+
pmk substitute -i Li96Ta6La11Cl72.cif -se Li2 -we none -ref La Ta
|
|
123
|
+
pmk ewald -i Li3YCl6.cif
|
|
124
|
+
pmk ewald -if Li3YCl6-all
|
|
125
|
+
pmk nep-rmse # writes energy/force/stress train txt files, rmse_value.txt, and terminal plots
|
|
126
|
+
pmk nep-rmse -select -xyz train.xyz # interactive candidate selection; writes candidate.xyz and accurate.xyz
|
|
127
|
+
pmk perturb -i example.xyz -atom 0.2 -lattice 0.03 -n 100 -o example-perturb-atom-0.2-lattice-0.03.xyz
|
|
128
|
+
pmk pca -i descriptor.out -o pca-descriptor.txt
|
|
129
|
+
pmk pca -i descriptor.out -o pca-descriptor.txt -fps 0.01 -it train.xyz
|
|
130
|
+
pmk umap -i descriptor.out -o umap-descriptor.txt -fps 0.01 -it train.xyz
|
|
131
|
+
pmk gpumd-thermo # current job, or recursively scan job folders
|
|
132
|
+
pmk gpumd-thermo -t thermo.out -in run.in
|
|
133
|
+
pmk trj-extract -it traj.xyz -in run.in -b 100 -e 200 -o traj-100ps-200ps.xyz
|
|
134
|
+
|
|
135
|
+
pmk rmsd a.cif b.cif # RMSD of two files -> rmsd.txt
|
|
136
|
+
pmk rmsd vasp-opted/ # all pairs in a folder -> rmsd.txt
|
|
137
|
+
pmk symmetrize -i opted.cif -symprec 0.01 -add_oxidation yes -o opted-symm.cif
|
|
138
|
+
pmk symmetrize -if my_cifs/ -symprec 0.01 -add_oxidation no -of my_cifs-symm
|
|
127
139
|
```
|
|
128
140
|
|
|
129
141
|
VASP input commands (`vasp-relax`, `vasp-static`) always produce **individual**
|
|
@@ -149,14 +161,20 @@ multi-structure trajectory and writes one job sub-folder per frame
|
|
|
149
161
|
folder also keeps a `frame_N.xyz`, so `Config_type` survives for a later
|
|
150
162
|
`vasp2xyz`.
|
|
151
163
|
|
|
152
|
-
|
|
164
|
+
`nep-rmse -select`, PCA FPS, and UMAP FPS copy selected extended-XYZ frame blocks directly from the input trajectory. No parser rewrites energy, stress, forces, positions, precision, or extra metadata.
|
|
165
|
+
|
|
166
|
+
For folder conversion, `convert -if INPUT -of OUTPUT` writes `.xyz` by default. Set another target extension with `-oe`, for example `-oe cif` or `-oe vasp`. Single-file and trajectory modes infer the target format from `-o` and `-ot`.
|
|
167
|
+
|
|
168
|
+
`gpumd-thermo` writes `temperature.txt`, `potential-energy.txt`, `pressure.txt`, `lattice-parameters.txt`, `volume.txt`, `lattice-angles.txt`, and a headless `thermo.png` in every detected GPUMD job folder. Its warning is a numerical reminder based on sustained drift or a level shift in the last `run` segment (or the last 80% when `run.in` has no `run` record); inspect the plot before deciding whether a trajectory is equilibrated.
|
|
169
|
+
|
|
170
|
+
Each command's full flag list is in `pmk <command> -help`.
|
|
153
171
|
|
|
154
172
|
For long VASP batch submission, run `submit-vasp` with `nohup` and `&` if you
|
|
155
173
|
want it to keep sleeping, checking the queue, and submitting new jobs after you
|
|
156
174
|
exit the terminal:
|
|
157
175
|
|
|
158
176
|
```bash
|
|
159
|
-
nohup
|
|
177
|
+
nohup pmk submit-vasp -subscript sub_vasp -queue slurm -max-job-num 30 > submit-vasp.log 2>&1 &
|
|
160
178
|
```
|
|
161
179
|
|
|
162
180
|
The command itself controls the loop: it submits until the active queue reaches
|
|
@@ -169,7 +187,7 @@ the background after logout.
|
|
|
169
187
|
cutoff is `0.7 * (selected covalent radius + reference covalent radius)` using
|
|
170
188
|
the covalent radii from Cordero et al., Dalton Trans., 2008, 2832-2838.
|
|
171
189
|
|
|
172
|
-
VASP-output readers (`vasp2xyz`, `ehull`, and other future VASP-output
|
|
190
|
+
VASP-output readers (`vasp2xyz`, `ehull`, `vasp-fe`, and other future VASP-output
|
|
173
191
|
commands) use the global priority `vaspout.h5 > vasprun.xml > OUTCAR`.
|
|
174
192
|
|
|
175
193
|
`ehull` auto-detects every sub-folder of the current path that contains a
|
|
@@ -184,23 +202,23 @@ a mixed Li-Y-Cl + La-O batch yields both `mp_cache_Li-Y-Cl.json` and
|
|
|
184
202
|
|
|
185
203
|
```
|
|
186
204
|
pymdkit/
|
|
187
|
-
|-- pyproject.toml # package metadata + the `
|
|
205
|
+
|-- pyproject.toml # package metadata + the `pmk` entry point
|
|
188
206
|
|-- README.md
|
|
189
207
|
`-- src/pymdkit/
|
|
190
208
|
|-- pymdkit_main.py # dispatcher: discovers and runs commands
|
|
191
209
|
`-- commands/ # one module per command
|
|
192
210
|
|-- _fileio.py # shared -i/-o/-if/-of helper (not a command)
|
|
193
211
|
|-- _vaspset.py # shared VASP input-set helper (not a command)
|
|
194
|
-
|--
|
|
212
|
+
|-- gpumd_group.py
|
|
195
213
|
|-- compute_ehull.py
|
|
196
214
|
|-- compute_rmsd.py
|
|
197
|
-
|--
|
|
198
|
-
|--
|
|
215
|
+
|-- ewald.py
|
|
216
|
+
|-- vasp_fe.py
|
|
199
217
|
|-- perturb.py
|
|
200
218
|
|-- nep_rmse.py
|
|
201
|
-
|--
|
|
219
|
+
|-- chemsys_entry.py
|
|
202
220
|
|-- submit_vasp.py
|
|
203
|
-
|--
|
|
221
|
+
|-- convert.py
|
|
204
222
|
|-- substitute.py
|
|
205
223
|
|-- supercell.py
|
|
206
224
|
|-- vasp2xyz.py
|
|
@@ -235,9 +253,9 @@ if __name__ == "__main__": # keeps the script runnable on its own
|
|
|
235
253
|
raise SystemExit(run(_p.parse_args()))
|
|
236
254
|
```
|
|
237
255
|
|
|
238
|
-
It will appear in `
|
|
256
|
+
It will appear in `pmk -help` automatically - no central registration needed.
|
|
239
257
|
Put heavy imports (pymatgen, ase, ...) inside `run()` where practical; the dispatcher
|
|
240
|
-
reads each command's name and help without importing it, so `
|
|
258
|
+
reads each command's name and help without importing it, so `pmk -help` stays
|
|
241
259
|
fast and a missing optional dependency only affects the one command that needs it.
|
|
242
260
|
|
|
243
261
|
## Running a script standalone
|
pymdkit-1.4.0/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# pymdkit
|
|
2
|
+
|
|
3
|
+
A single command-line tool that bundles a collection of atomistic / molecular-dynamics
|
|
4
|
+
structure scripts behind one executable: `pmk`. Instead of copying individual
|
|
5
|
+
scripts into each working folder and running `python some_script.py`, you install
|
|
6
|
+
`pymdkit` once and call any tool from anywhere as `pmk <command> [options]`.
|
|
7
|
+
|
|
8
|
+
Every command exposes named `-flags` (no positional guessing), and each underlying
|
|
9
|
+
script is still runnable on its own.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
Create a clean conda environment, activate it, then install `pymdkit` with pip:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
conda create -n pymdkit python=3.10
|
|
17
|
+
conda activate pymdkit
|
|
18
|
+
pip install pymdkit
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
This installs the `pmk` command into the active conda environment, together
|
|
22
|
+
with its direct dependencies, including ASE, pymatgen, py4vasp-core, dpdata, matplotlib, and UMAP. Some of these packages may install their own transitive dependencies.
|
|
23
|
+
|
|
24
|
+
Verify:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pmk -version
|
|
28
|
+
pmk -help # lists every command
|
|
29
|
+
pmk <command> -help # shows that command's flags
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
Commands that transform structures accept either a single file (`-i`/`-o`) or a
|
|
35
|
+
whole folder (`-if`/`-of`); commands that analyse VASP runs scan the current
|
|
36
|
+
directory for job sub-folders automatically.
|
|
37
|
+
|
|
38
|
+
| Command | What it does |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `gpumd-group` | Tag atoms with a GPUMD group index by element order |
|
|
41
|
+
| `ewald` | Compute CIF electrostatic energy with pymatgen EwaldSummation |
|
|
42
|
+
| `ehull` | Auto-detect VASP job folders and compute E_hull vs Materials Project |
|
|
43
|
+
| `vasp-fe` | List VASP job final energies from lowest to highest |
|
|
44
|
+
| `gather-contcar` | Collect CONTCARs from VASP job folders into one folder, renamed `<folder>.vasp` |
|
|
45
|
+
| `gpumd-thermo` | Export and plot GPUMD thermo data and detect sustained equilibrium changes |
|
|
46
|
+
| `pca` | Reduce descriptor data to two dimensions; optional FPS sampling |
|
|
47
|
+
| `trj-extract` | Extract a GPUMD XYZ trajectory by time range |
|
|
48
|
+
| `umap` | Reduce descriptor data to two dimensions with UMAP; optional FPS sampling |
|
|
49
|
+
| `msd` | Diffusivity & conductivity from GPUMD MSD jobs (auto-scans `<structure>/<temp>/`) |
|
|
50
|
+
| `nep-rmse` | Compute NEP energy/force/stress RMSE with terminal plots and optional candidate selection |
|
|
51
|
+
| `perturb` | Generate perturbed structures with dpdata |
|
|
52
|
+
| `vasp2xyz` | Collect SCF-converged VASP job folders (any name) into one extxyz file |
|
|
53
|
+
| `submit-vasp` | Submit/resubmit VASP job folders while limiting active queue jobs |
|
|
54
|
+
| `rmsd` | Compute RMSD between two structure files, or all pairs in a folder |
|
|
55
|
+
| `chemsys-entry` | Download stable Materials Project structures for a chemical system |
|
|
56
|
+
| `convert` | Convert structures, trajectories, or folders between ASE/pymatgen formats |
|
|
57
|
+
| `substitute` | Randomly substitute or remove selected atoms/sites from a structure |
|
|
58
|
+
| `supercell` | Build a supercell with cell lengths capped at a maximum (Angstrom); optional per-temperature GPUMD setup |
|
|
59
|
+
| `symmetrize` | Import space-group symmetry into a structure file (or folder) -> CIF |
|
|
60
|
+
| `vasp-relax` | Write VASP relaxation inputs for a structure (or folder); INCAR tags overridable |
|
|
61
|
+
| `vasp-static` | Write VASP static / single-point inputs for a structure (or folder) |
|
|
62
|
+
|
|
63
|
+
## Examples
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pmk gpumd-group -i opted.cif -elements Li Y Cl -o model.xyz
|
|
67
|
+
pmk gpumd-group -if cifs/ -elements Li Y Cl -of cifs-grouped/ # whole folder
|
|
68
|
+
pmk gpumd-group -elements Li Y Cl # scan subfolders, tag each model.xyz in place
|
|
69
|
+
pmk convert -i opted.vasp -o opted.xyz # convert one structure
|
|
70
|
+
pmk convert -if vasp-opted -of cif-opted -oe cif # folder conversion target format
|
|
71
|
+
pmk convert -it train.xyz -ot train.extxyz # convert a complete trajectory
|
|
72
|
+
pmk supercell -i opted.vasp -o sc.vasp -max-abc 20 # cell lengths <= 20 A
|
|
73
|
+
pmk supercell -if vasp-opted -max-abc 20 -individual # per-structure ./<name>/<name>.<ext>
|
|
74
|
+
pmk supercell -if extxyz-opted -max-abc 24 -individual -temp 500 600 -md-if input-files -add-groups Li Y Cl
|
|
75
|
+
# GPUMD: ./<name>/model.xyz (grouped) + ./<name>/<T>/ jobs
|
|
76
|
+
pmk vasp-relax -i opted.vasp # relax inputs in current dir
|
|
77
|
+
pmk vasp-relax -if optimal_occupancy # one ./<name>/ job folder per structure
|
|
78
|
+
pmk vasp-static -if cifs/ -custom-setting my_incar.txt # static inputs, custom INCAR
|
|
79
|
+
pmk vasp-static -it traj.xyz # one ./frame_N/ job per trajectory frame
|
|
80
|
+
pmk msd # scans <structure>/<temp>/ -> per-job msd/ + msd_summary.txt
|
|
81
|
+
pmk msd -diffuse_ion Li -ion_charge 1 # choose the mobile ion for conductivity
|
|
82
|
+
pmk chemsys-entry -s Li La Ta Cl # MP stable entries -> Li-La-Ta-Cl-stable-entries/
|
|
83
|
+
pmk ehull -mp-api-key $MP_API_KEY # scans ./ for VASP jobs -> ehull.txt
|
|
84
|
+
pmk ehull -local Li-La-Ta-Cl-stable-entries-opted
|
|
85
|
+
pmk vasp-fe # scans ./ for VASP jobs -> final-energy.txt with convergence status
|
|
86
|
+
pmk gather-contcar -of vasp-opted # CONTCARs -> vasp-opted/<folder>.vasp
|
|
87
|
+
pmk gather-contcar -of vasp-opted -ehull 0.028 # only structures with E_hull < 0.028 eV/atom
|
|
88
|
+
pmk vasp2xyz # scans ./ for VASP output folders -> scf-converged.xyz
|
|
89
|
+
pmk vasp2xyz -position-only # write positions only, without energy/forces/stress
|
|
90
|
+
pmk submit-vasp -subscript sub_vasp -queue slurm -max-job-num 30
|
|
91
|
+
nohup pmk submit-vasp -subscript sub_vasp -queue slurm -max-job-num 30 > submit-vasp.log 2>&1 &
|
|
92
|
+
pmk substitute -i Li3YCl6.cif -se Li -sn 3 -we Na -wn 3 -on 100
|
|
93
|
+
pmk substitute -i Li3YCl6.cif -se Li -sn 3 -we none -on 100
|
|
94
|
+
pmk substitute -i Li96Ta6La11Cl72.cif -se Li1 Li2 -sn 20 67 -we none -on 100
|
|
95
|
+
pmk substitute -i Li96Ta6La11Cl72.cif -se Li2 -we none -ref La Ta -d 1.01 1.02
|
|
96
|
+
pmk substitute -i Li96Ta6La11Cl72.cif -se Li2 -we none -ref La Ta
|
|
97
|
+
pmk ewald -i Li3YCl6.cif
|
|
98
|
+
pmk ewald -if Li3YCl6-all
|
|
99
|
+
pmk nep-rmse # writes energy/force/stress train txt files, rmse_value.txt, and terminal plots
|
|
100
|
+
pmk nep-rmse -select -xyz train.xyz # interactive candidate selection; writes candidate.xyz and accurate.xyz
|
|
101
|
+
pmk perturb -i example.xyz -atom 0.2 -lattice 0.03 -n 100 -o example-perturb-atom-0.2-lattice-0.03.xyz
|
|
102
|
+
pmk pca -i descriptor.out -o pca-descriptor.txt
|
|
103
|
+
pmk pca -i descriptor.out -o pca-descriptor.txt -fps 0.01 -it train.xyz
|
|
104
|
+
pmk umap -i descriptor.out -o umap-descriptor.txt -fps 0.01 -it train.xyz
|
|
105
|
+
pmk gpumd-thermo # current job, or recursively scan job folders
|
|
106
|
+
pmk gpumd-thermo -t thermo.out -in run.in
|
|
107
|
+
pmk trj-extract -it traj.xyz -in run.in -b 100 -e 200 -o traj-100ps-200ps.xyz
|
|
108
|
+
|
|
109
|
+
pmk rmsd a.cif b.cif # RMSD of two files -> rmsd.txt
|
|
110
|
+
pmk rmsd vasp-opted/ # all pairs in a folder -> rmsd.txt
|
|
111
|
+
pmk symmetrize -i opted.cif -symprec 0.01 -add_oxidation yes -o opted-symm.cif
|
|
112
|
+
pmk symmetrize -if my_cifs/ -symprec 0.01 -add_oxidation no -of my_cifs-symm
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
VASP input commands (`vasp-relax`, `vasp-static`) always produce **individual**
|
|
116
|
+
jobs (one structure per folder): `-i` writes into the current dir (or `-o`),
|
|
117
|
+
`-if` creates one `./<name>/` folder per structure, and `-it` creates one
|
|
118
|
+
`./frame_N/` folder per trajectory frame - all directly in the current path.
|
|
119
|
+
|
|
120
|
+
They start from sensible default INCAR settings; override them by passing a
|
|
121
|
+
settings file with `-custom-setting FILE`. The file may be a Python-dict block
|
|
122
|
+
or `KEY = VALUE` lines (a `None`/blank value clears a tag):
|
|
123
|
+
|
|
124
|
+
```text
|
|
125
|
+
custom_settings = {
|
|
126
|
+
"ENCUT": "600.0",
|
|
127
|
+
"ISIF": "3",
|
|
128
|
+
"MAGMOM": None
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`vasp-static -it traj.xyz` (also available on `vasp-relax`) reads a
|
|
133
|
+
multi-structure trajectory and writes one job sub-folder per frame
|
|
134
|
+
(`frame_1/`, `frame_2/`, ..., prefix configurable via `-frame-prefix`). Each
|
|
135
|
+
folder also keeps a `frame_N.xyz`, so `Config_type` survives for a later
|
|
136
|
+
`vasp2xyz`.
|
|
137
|
+
|
|
138
|
+
`nep-rmse -select`, PCA FPS, and UMAP FPS copy selected extended-XYZ frame blocks directly from the input trajectory. No parser rewrites energy, stress, forces, positions, precision, or extra metadata.
|
|
139
|
+
|
|
140
|
+
For folder conversion, `convert -if INPUT -of OUTPUT` writes `.xyz` by default. Set another target extension with `-oe`, for example `-oe cif` or `-oe vasp`. Single-file and trajectory modes infer the target format from `-o` and `-ot`.
|
|
141
|
+
|
|
142
|
+
`gpumd-thermo` writes `temperature.txt`, `potential-energy.txt`, `pressure.txt`, `lattice-parameters.txt`, `volume.txt`, `lattice-angles.txt`, and a headless `thermo.png` in every detected GPUMD job folder. Its warning is a numerical reminder based on sustained drift or a level shift in the last `run` segment (or the last 80% when `run.in` has no `run` record); inspect the plot before deciding whether a trajectory is equilibrated.
|
|
143
|
+
|
|
144
|
+
Each command's full flag list is in `pmk <command> -help`.
|
|
145
|
+
|
|
146
|
+
For long VASP batch submission, run `submit-vasp` with `nohup` and `&` if you
|
|
147
|
+
want it to keep sleeping, checking the queue, and submitting new jobs after you
|
|
148
|
+
exit the terminal:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
nohup pmk submit-vasp -subscript sub_vasp -queue slurm -max-job-num 30 > submit-vasp.log 2>&1 &
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The command itself controls the loop: it submits until the active queue reaches
|
|
155
|
+
`-max-job-num`, sleeps when the queue is full, checks again, and continues until
|
|
156
|
+
all needed jobs are submitted. `nohup ... &` is what makes that loop continue in
|
|
157
|
+
the background after logout.
|
|
158
|
+
|
|
159
|
+
`substitute -ref` removes selected sites near reference sites and writes one
|
|
160
|
+
`<input-stem>_substitute.cif` in the current path. If `-d` is omitted, each
|
|
161
|
+
cutoff is `0.7 * (selected covalent radius + reference covalent radius)` using
|
|
162
|
+
the covalent radii from Cordero et al., Dalton Trans., 2008, 2832-2838.
|
|
163
|
+
|
|
164
|
+
VASP-output readers (`vasp2xyz`, `ehull`, `vasp-fe`, and other future VASP-output
|
|
165
|
+
commands) use the global priority `vaspout.h5 > vasprun.xml > OUTCAR`.
|
|
166
|
+
|
|
167
|
+
`ehull` auto-detects every sub-folder of the current path that contains a
|
|
168
|
+
supported VASP output, groups them by chemical system (elements ordered by
|
|
169
|
+
electronegativity, e.g. `Li-Y-Cl`), and builds/reuses one `mp_cache_<system>.json`
|
|
170
|
+
per system - so a pure Li-Y-Cl batch yields a single `mp_cache_Li-Y-Cl.json`, while
|
|
171
|
+
a mixed Li-Y-Cl + La-O batch yields both `mp_cache_Li-Y-Cl.json` and
|
|
172
|
+
`mp_cache_La-O.json`. (Formation energy is reported alongside E_hull in
|
|
173
|
+
`ehull.txt`.)
|
|
174
|
+
|
|
175
|
+
## Layout
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
pymdkit/
|
|
179
|
+
|-- pyproject.toml # package metadata + the `pmk` entry point
|
|
180
|
+
|-- README.md
|
|
181
|
+
`-- src/pymdkit/
|
|
182
|
+
|-- pymdkit_main.py # dispatcher: discovers and runs commands
|
|
183
|
+
`-- commands/ # one module per command
|
|
184
|
+
|-- _fileio.py # shared -i/-o/-if/-of helper (not a command)
|
|
185
|
+
|-- _vaspset.py # shared VASP input-set helper (not a command)
|
|
186
|
+
|-- gpumd_group.py
|
|
187
|
+
|-- compute_ehull.py
|
|
188
|
+
|-- compute_rmsd.py
|
|
189
|
+
|-- ewald.py
|
|
190
|
+
|-- vasp_fe.py
|
|
191
|
+
|-- perturb.py
|
|
192
|
+
|-- nep_rmse.py
|
|
193
|
+
|-- chemsys_entry.py
|
|
194
|
+
|-- submit_vasp.py
|
|
195
|
+
|-- convert.py
|
|
196
|
+
|-- substitute.py
|
|
197
|
+
|-- supercell.py
|
|
198
|
+
|-- vasp2xyz.py
|
|
199
|
+
|-- vasp_relax.py
|
|
200
|
+
|-- vasp_static.py
|
|
201
|
+
|-- ...
|
|
202
|
+
`-- symmetrize.py
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Modules whose name starts with `_` are shared helpers and are skipped by the
|
|
206
|
+
dispatcher, so they never appear as commands.
|
|
207
|
+
|
|
208
|
+
## Adding a new tool later
|
|
209
|
+
|
|
210
|
+
Drop a module in `src/pymdkit/commands/` that defines four things:
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
COMMAND = "my-tool" # the subcommand name you'll type
|
|
214
|
+
HELP = "One-line description."
|
|
215
|
+
|
|
216
|
+
def add_arguments(parser): # register flags
|
|
217
|
+
parser.add_argument("-input", required=True)
|
|
218
|
+
|
|
219
|
+
def run(args): # do the work; return an exit code (0 = ok)
|
|
220
|
+
...
|
|
221
|
+
return 0
|
|
222
|
+
|
|
223
|
+
if __name__ == "__main__": # keeps the script runnable on its own
|
|
224
|
+
import argparse
|
|
225
|
+
_p = argparse.ArgumentParser(description=__doc__)
|
|
226
|
+
add_arguments(_p)
|
|
227
|
+
raise SystemExit(run(_p.parse_args()))
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
It will appear in `pmk -help` automatically - no central registration needed.
|
|
231
|
+
Put heavy imports (pymatgen, ase, ...) inside `run()` where practical; the dispatcher
|
|
232
|
+
reads each command's name and help without importing it, so `pmk -help` stays
|
|
233
|
+
fast and a missing optional dependency only affects the one command that needs it.
|
|
234
|
+
|
|
235
|
+
## Running a script standalone
|
|
236
|
+
|
|
237
|
+
Every command module still works directly, which is handy for debugging:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
python src/pymdkit/commands/supercell.py -i in.cif -max-abc 20 -o sc.vasp
|
|
241
|
+
```
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pymdkit"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.4.0"
|
|
8
8
|
description = "A unified command-line toolkit for atomistic / MD structure workflows."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -20,9 +20,9 @@ classifiers = [
|
|
|
20
20
|
"Topic :: Scientific/Engineering :: Physics",
|
|
21
21
|
]
|
|
22
22
|
|
|
23
|
-
# All dependencies are installed up front so a plain
|
|
23
|
+
# All dependencies are installed up front so a plain ppip install pymdkitp
|
|
24
24
|
# gives a fully working CLI. Heavy libraries are still imported lazily inside
|
|
25
|
-
# individual commands, so the dispatcher and
|
|
25
|
+
# individual commands, so the dispatcher and pmk -help stay fast.
|
|
26
26
|
dependencies = [
|
|
27
27
|
"numpy",
|
|
28
28
|
"ase",
|
|
@@ -31,11 +31,13 @@ dependencies = [
|
|
|
31
31
|
"py4vasp-core",
|
|
32
32
|
"pyxtal",
|
|
33
33
|
"dpdata",
|
|
34
|
+
"matplotlib",
|
|
35
|
+
"umap-learn",
|
|
34
36
|
]
|
|
35
37
|
|
|
36
38
|
[project.scripts]
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
+
# The distribution remains pymdkit; the concise public executable is ppmkp.
|
|
40
|
+
pmk = "pymdkit.pymdkit_main:main"
|
|
39
41
|
|
|
40
42
|
[tool.setuptools.packages.find]
|
|
41
43
|
where = ["src"]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Exact, byte-preserving helpers for extended-XYZ trajectories."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def read_blocks(path):
|
|
9
|
+
"""Return ``(blocks, atom_counts)`` without parsing or reformatting data."""
|
|
10
|
+
path = Path(path)
|
|
11
|
+
lines = path.read_bytes().splitlines(keepends=True)
|
|
12
|
+
blocks = []
|
|
13
|
+
atom_counts = []
|
|
14
|
+
index = 0
|
|
15
|
+
while index < len(lines):
|
|
16
|
+
if not lines[index].strip():
|
|
17
|
+
index += 1
|
|
18
|
+
continue
|
|
19
|
+
try:
|
|
20
|
+
count = int(lines[index].strip())
|
|
21
|
+
except ValueError as exc:
|
|
22
|
+
raise ValueError(
|
|
23
|
+
f"{path}: expected an atom count at line {index + 1}"
|
|
24
|
+
) from exc
|
|
25
|
+
stop = index + count + 2
|
|
26
|
+
if stop > len(lines):
|
|
27
|
+
raise ValueError(f"{path}: incomplete frame beginning at line {index + 1}")
|
|
28
|
+
blocks.append(b"".join(lines[index:stop]))
|
|
29
|
+
atom_counts.append(count)
|
|
30
|
+
index = stop
|
|
31
|
+
return blocks, atom_counts
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def write_blocks(path, blocks, indices):
|
|
35
|
+
"""Write selected frames exactly as they appeared in the source file."""
|
|
36
|
+
Path(path).write_bytes(b"".join(blocks[int(index)] for index in indices))
|