pymdkit 1.7.2__tar.gz → 1.7.4__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.
Files changed (98) hide show
  1. pymdkit-1.7.4/CHANGELOG.md +25 -0
  2. pymdkit-1.7.4/MANIFEST.in +4 -0
  3. {pymdkit-1.7.2 → pymdkit-1.7.4}/PKG-INFO +384 -7
  4. {pymdkit-1.7.2 → pymdkit-1.7.4}/README.md +383 -6
  5. {pymdkit-1.7.2 → pymdkit-1.7.4}/pyproject.toml +1 -1
  6. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/__init__.py +1 -1
  7. pymdkit-1.7.4/src/pymdkit/commands/_gpumd_run.py +121 -0
  8. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_gpumd_thermo.py +222 -265
  9. pymdkit-1.7.4/src/pymdkit/commands/_msd_auto.py +269 -0
  10. pymdkit-1.7.4/src/pymdkit/commands/_msd_conductivity.py +19 -0
  11. pymdkit-1.7.4/src/pymdkit/commands/_msd_coordinates.py +105 -0
  12. pymdkit-1.7.4/src/pymdkit/commands/_msd_fit.py +308 -0
  13. pymdkit-1.7.4/src/pymdkit/commands/_msd_io.py +131 -0
  14. pymdkit-1.7.4/src/pymdkit/commands/_msd_provenance.py +27 -0
  15. pymdkit-1.7.4/src/pymdkit/commands/_msd_range.py +73 -0
  16. pymdkit-1.7.4/src/pymdkit/commands/_msd_thermo.py +44 -0
  17. pymdkit-1.7.4/src/pymdkit/commands/_msd_uncertainty.py +260 -0
  18. pymdkit-1.7.4/src/pymdkit/commands/_pred_msd_plan.py +271 -0
  19. pymdkit-1.7.4/src/pymdkit/commands/_pred_msd_reference.py +213 -0
  20. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/gpumd_job.py +69 -3
  21. pymdkit-1.7.4/src/pymdkit/commands/msd.py +360 -0
  22. pymdkit-1.7.4/src/pymdkit/commands/pred_msd_time.py +211 -0
  23. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/pymdkit_main.py +3 -1
  24. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit.egg-info/PKG-INFO +384 -7
  25. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit.egg-info/SOURCES.txt +25 -1
  26. pymdkit-1.7.4/tests/data/88-Li2YCl3-63-d1.cif +54 -0
  27. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_gpumd_out.py +128 -0
  28. pymdkit-1.7.4/tests/test_msd_auto.py +265 -0
  29. pymdkit-1.7.4/tests/test_msd_fit.py +123 -0
  30. pymdkit-1.7.4/tests/test_msd_large.py +179 -0
  31. pymdkit-1.7.4/tests/test_msd_phase3.py +578 -0
  32. pymdkit-1.7.4/tests/test_msd_range.py +240 -0
  33. pymdkit-1.7.4/tests/test_msd_uncertainty.py +183 -0
  34. pymdkit-1.7.4/tests/test_pred_msd_time.py +229 -0
  35. {pymdkit-1.7.2 → pymdkit-1.7.4}/LICENSE +0 -0
  36. {pymdkit-1.7.2 → pymdkit-1.7.4}/setup.cfg +0 -0
  37. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/_config.py +0 -0
  38. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/_logging.py +0 -0
  39. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/__init__.py +0 -0
  40. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_cifio.py +0 -0
  41. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_extxyz.py +0 -0
  42. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_fileio.py +0 -0
  43. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_geometry.py +0 -0
  44. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_gpumd.py +0 -0
  45. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_gpumd_final_structure.py +0 -0
  46. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_gpumd_msd.py +0 -0
  47. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_gpumd_status.py +0 -0
  48. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_lattice.py +0 -0
  49. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_oxidation.py +0 -0
  50. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_parallel.py +0 -0
  51. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_precision.py +0 -0
  52. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_reduction.py +0 -0
  53. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_submit.py +0 -0
  54. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_submit_vasp.py +0 -0
  55. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_supercell.py +0 -0
  56. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_symmetry.py +0 -0
  57. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_vasp_ehull.py +0 -0
  58. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_vasp_final_structure.py +0 -0
  59. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_vasp_nep.py +0 -0
  60. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_vasp_output.py +0 -0
  61. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/_vaspset.py +0 -0
  62. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/chemsys_entry.py +0 -0
  63. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/compute_rmsd.py +0 -0
  64. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/config.py +0 -0
  65. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/convert.py +0 -0
  66. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/dope.py +0 -0
  67. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/ewald.py +0 -0
  68. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/gpumd_out.py +0 -0
  69. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/nep_rmse.py +0 -0
  70. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/perturb.py +0 -0
  71. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/rd.py +0 -0
  72. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/realloc_occ.py +0 -0
  73. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/submit.py +0 -0
  74. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/supercell.py +0 -0
  75. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/trjconv.py +0 -0
  76. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/vasp_job.py +0 -0
  77. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit/commands/vasp_out.py +0 -0
  78. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit.egg-info/dependency_links.txt +0 -0
  79. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit.egg-info/entry_points.txt +0 -0
  80. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit.egg-info/requires.txt +0 -0
  81. {pymdkit-1.7.2 → pymdkit-1.7.4}/src/pymdkit.egg-info/top_level.txt +0 -0
  82. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_config_logging.py +0 -0
  83. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_convert.py +0 -0
  84. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_ehull.py +0 -0
  85. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_lattice_symmetry.py +0 -0
  86. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_parallel.py +0 -0
  87. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_progress.py +0 -0
  88. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_realloc_occ.py +0 -0
  89. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_rmsd_gpu.py +0 -0
  90. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_rmsd_max.py +0 -0
  91. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_rmsd_two_folder.py +0 -0
  92. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_submit.py +0 -0
  93. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_v165.py +0 -0
  94. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_v170_job_infrastructure.py +0 -0
  95. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_v170_vasp_consolidation.py +0 -0
  96. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_v172_vasp_writing.py +0 -0
  97. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_vasp_out.py +0 -0
  98. {pymdkit-1.7.2 → pymdkit-1.7.4}/tests/test_vaspset.py +0 -0
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ ## 1.7.4
4
+
5
+ - `pmk msd -ne` retains finite, positive Einstein diffusion coefficients and
6
+ Nernst–Einstein conductivity when the fit-quality diagnostics would reject the
7
+ window. The result is reported and aggregated as WARNING, with the original
8
+ diagnostic details preserved. This applies to automatic and manual windows.
9
+ - Missing valid regression, failed requested estimators, and invalid NE inputs
10
+ still fail the calculation and preserve existing aggregate summaries.
11
+
12
+ ## 1.7.3
13
+
14
+ - `pmk msd` analyzes fixed-cell GPUMD NVT trajectories, selects or accepts a
15
+ fitting window, and optionally reports Nernst–Einstein conductivity. It uses
16
+ free-intercept OLS by default. Optional WLS and GLS also estimate the intercept.
17
+ Forced-origin fitting has been removed from production.
18
+ - `pmk pred-msd-time` uses validated full-trajectory OLS references to forecast
19
+ higher-temperature Li conductivity, diffusion, and NVT production duration.
20
+ The Arrhenius forecast and square-root duration scaling are planning heuristics.
21
+ The durations carry no guarantee of MSD convergence.
22
+ - `pmk gpumd-job -msd-time` generates GPUMD 4.2-compatible jobs with explicit
23
+ NVT temperatures, run lengths, and optional `compute_msd` sample counts.
24
+ Fixed-cell NVT production is required for MSD analysis. Earlier NPT equilibration
25
+ is supported when its frames are excluded from the analyzed trajectory.
@@ -0,0 +1,4 @@
1
+ include CHANGELOG.md
2
+ include tests/data/88-Li2YCl3-63-d1.cif
3
+ exclude tests/test_benchmark_msd_io.py
4
+ prune devtools
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymdkit
3
- Version: 1.7.2
3
+ Version: 1.7.4
4
4
  Summary: A Python command-line toolkit for high-throughput atomistic workflows in AI-driven materials design.
5
5
  Author-email: Yueda Wang <ydwang0608@ustc.edu.cn>
6
6
  License-Expression: GPL-3.0-or-later
@@ -36,6 +36,26 @@ materials design. Install `pymdkit` once and call its tools from anywhere as
36
36
  Commands expose explicit, documented CLI interfaces designed for reproducible shell,
37
37
  HPC, and AI-agent workflows, and each underlying script is still runnable on its own.
38
38
 
39
+ ## 1.7.4 release notes
40
+
41
+ - `pmk msd -ne` retains valid Einstein diffusion coefficients and conductivity
42
+ as WARNING when fit quality would otherwise be REJECT. This applies to
43
+ automatic and manual windows and preserves the individual diagnostic results.
44
+ - Missing valid regression, failed requested estimators, and invalid NE inputs
45
+ still cause calculation errors. Without `-ne`, fit-quality rejection still
46
+ withholds diffusion coefficients.
47
+
48
+ ## 1.7.3 release notes
49
+
50
+ - `pmk msd` analyzes GPUMD trajectories from fixed-cell NVT production. OLS is
51
+ the default, and OLS, WLS and GLS all fit a free intercept. Forced-origin
52
+ fitting has been removed from production. Changing-cell MSD is outside scope.
53
+ - `pmk pred-msd-time` uses validated free-intercept OLS references for
54
+ higher-temperature Li transport and production-time planning. The duration
55
+ heuristic carries no guarantee of MSD convergence.
56
+ - `pmk gpumd-job -msd-time` turns predictions into GPUMD 4.2-compatible NVT
57
+ job inputs. Earlier NPT equilibration can precede the analyzed production.
58
+
39
59
  ## Install
40
60
 
41
61
  ### Online installation
@@ -86,7 +106,7 @@ installed.
86
106
  On a machine with Internet access, run:
87
107
 
88
108
  ```bash
89
- python -m pip download pymdkit==1.7.2 -d pymdkit-offline
109
+ python -m pip download pymdkit==1.7.4 -d pymdkit-offline
90
110
  ```
91
111
 
92
112
  This downloads `pymdkit` and the dependencies resolved by pip into the
@@ -94,14 +114,14 @@ This downloads `pymdkit` and the dependencies resolved by pip into the
94
114
  system. Then, inside the target pymdkit Python or conda environment, run:
95
115
 
96
116
  ```bash
97
- python -m pip install --no-index --find-links=pymdkit-offline pymdkit==1.7.2
117
+ python -m pip install --no-index --find-links=pymdkit-offline pymdkit==1.7.4
98
118
  ```
99
119
 
100
120
  For optional GPU use, prepare the bundle on a networked machine compatible with
101
121
  the target HPC platform and Python environment:
102
122
 
103
123
  ```bash
104
- python -m pip download "pymdkit[gpu-cuda12]==1.7.2" -d pymdkit-offline
124
+ python -m pip download "pymdkit[gpu-cuda12]==1.7.4" -d pymdkit-offline
105
125
  ```
106
126
 
107
127
  Transfer the whole `pymdkit-offline` directory, then install from it on the
@@ -109,7 +129,7 @@ target system:
109
129
 
110
130
  ```bash
111
131
  python -m pip install --no-index --find-links=pymdkit-offline \
112
- "pymdkit[gpu-cuda12]==1.7.2"
132
+ "pymdkit[gpu-cuda12]==1.7.4"
113
133
  ```
114
134
 
115
135
  This GPU bundle includes the optional `cupy-cuda12x` package. Its wheels must also
@@ -190,6 +210,7 @@ preserve occupancy, oxidation, symmetry, and Wyckoff metadata.
190
210
  | `dope` | Dope structures by substituting or removing selected atoms/sites |
191
211
  | `ewald` | Compute CIF electrostatic energy |
192
212
  | `gpumd-job` | Create supercell, temperature, potential, input, and grouped GPUMD jobs |
213
+ | `pred-msd-time` | Predict Li conductivity, diffusion and NVT production durations from GPUMD MSD |
193
214
  | `gpumd-out` | Export GPUMD thermo/MSD results or gather final structures |
194
215
  | `mp-chemsys` | Download stable Materials Project structures for a chemical system |
195
216
  | `nep-rmse` | Compute NEP energy/force/stress RMSE and select candidates |
@@ -425,8 +446,13 @@ pmk gpumd-out -save-fs [-entry-path DIR] [-fs-name FILENAME] (-of DIR | -output-
425
446
  ```
426
447
 
427
448
  `-entry-path` defaults to `.`. Thermo mode defaults to `thermo.out` and
428
- `run.in`, preserving the per-job text tables, `thermo.png`, and
429
- `abnormal-time.txt` when an abnormal interval is detected. MSD mode defaults
449
+ `run.in`, writing per-job `temperature.txt`, `potential-energy.txt`,
450
+ `pressure.txt`, `lattice-parameters.txt`, `volume.txt`, `lattice-angles.txt`,
451
+ and the six-panel `thermo.png`. Abnormal-fluctuation diagnostics remain in
452
+ console warnings and `gpumd-out.log`; the plot has no abnormal-region shading
453
+ or legend. Thermo mode no longer generates `abnormal-time.txt` and removes
454
+ that exact stale file only after successfully exporting a job's tables and
455
+ plot. MSD mode defaults
430
456
  to mobile ion `Li` with charge `1`, writes
431
457
  `sigma-sdc-summary.txt` at the entry root, and preserves each job's
432
458
  `msd/group_*_msd.txt`, `group_*_sdc.txt`, and `group_*_results.txt`.
@@ -720,3 +746,354 @@ Every command module still works directly, which is handy for debugging:
720
746
  ```bash
721
747
  python src/pymdkit/commands/supercell.py -i in.cif -close-abc 20 -o sc.vasp
722
748
  ```
749
+ ## Atomic trajectory MSD
750
+
751
+ ```bash
752
+ pmk msd -group 0
753
+ pmk msd -group 0 -ne
754
+ pmk msd -group 0 -ne -charge 2
755
+ pmk msd -group 0 -fit-method gls
756
+ pmk msd -group 0 -fit-range 10 100
757
+ pmk msd -group 0 -ne -trajectory-range 0 10
758
+ pmk msd -group 0 -ne -trajectory-range 10 20
759
+ ```
760
+
761
+ `-md-program gpumd` is the default. The current directory and calculation
762
+ subdirectories are searched deterministically, excluding generated `msd`, hidden,
763
+ environment and build directories. Each calculation needs `model.xyz`, `run.in`
764
+ and the native full-system trajectory named by `dump_xyz`, or `dump.xyz` from
765
+ legacy `dump_exyz interval velocity_flag force_flag`. Group selection uses the
766
+ first grouping method in `model.xyz`. Missing group labels are an error.
767
+
768
+ Both `dump_xyz interval filename properties...` and GPUMD 4.2's
769
+ `dump_xyz grouping_method group_id interval filename properties...` are supported.
770
+ For example, `dump_xyz -1 0 200 dump.xyz group unwrapped_position` saves the whole
771
+ system every 200 steps. Legacy grouping methods must be negative (full system);
772
+ the group ID must be an integer and is ignored in this mode. Subset trajectories
773
+ are rejected because whole-system COM correction requires every atom. Legacy
774
+ `group` and modern `group_labels` properties are supported. Earlier NPT
775
+ equilibration without trajectory output is allowed before fixed-cell NVT production.
776
+ Directories with active unresolved `target_t`, `${...}` or `{{...}}` placeholders
777
+ in `run.in` are skipped with a reason; commented placeholders are ignored.
778
+
779
+ This is the mean of individual atomic squared displacements, **not group-COM
780
+ MSD**. Every frame is streamed through a native GPUMD numeric parser (other
781
+ extxyz schemas retain the ASE fallback), then selected coordinates are stored
782
+ in a temporary float64 memmap. All system atoms contribute to mass-weighted COM
783
+ displacement removal using ASE tabulated atomic masses. Species order, atom count,
784
+ PBC flags, and group/ID columns (when present) are checked against the model.
785
+ Native GPUMD full-system row ordering is required: externally sorted same-element
786
+ atoms without stable IDs cannot be identified and must not be supplied.
787
+
788
+ For fixed triclinic cells, consistent `unwrapped_position` is preferred; otherwise
789
+ ASE's general lattice minimum-image algorithm accumulates successive displacements.
790
+ Wrapped output must be frequent enough to resolve each displacement uniquely;
791
+ multiple unseen boundary crossings cannot be recovered from saved frames.
792
+ **MSD analysis supports fixed-cell NVT production.** NPT and changing-cell
793
+ production are rejected, including pure affine deformation.
794
+
795
+ The default `--fit-window auto` searches atom-based total MSD lag windows using
796
+ log-log OLS beta, then calculates D independently with free-intercept Einstein
797
+ OLS (directional slopes/2; total is their arithmetic mean). Following
798
+ [MDTransport (2026)](https://doi.org/10.1021/acs.jcim.6c00558), the search grid
799
+ is 100 ps. The default minimum duration is `min(T/2, 8000 ps)`, a continuous
800
+ pymdkit engineering adaptation of the published piecewise rule that avoids
801
+ infeasible windows immediately above 10 ns. Following
802
+ [He et al. (2018)](https://doi.org/10.1038/s41524-018-0074-y), every automatic
803
+ upper lag is strictly below 0.7T. T is saved frame count times frame interval,
804
+ not the absolute simulation timestamp. Grid boundaries map to nearest MSD
805
+ samples; first positive lag and last allowed lag are included as endpoints.
806
+ The minimum duration is never silently relaxed.
807
+
808
+ Controls are `--min-fit-window PS`, `--fit-window-step PS`, and
809
+ `--beta-tolerance VALUE` (default 0.075, maximum 0.20). Among beta-qualified
810
+ windows, choose D closest to the pool median, then smaller beta deviation, then
811
+ longer duration. Without qualified windows choose minimum beta deviation.
812
+ Separate `beta_status`, `intercept_status`, `einstein_slope_status` and
813
+ `overall_status` distinguish raw beta from affine Einstein model consistency
814
+ and slope stability. Beta thresholds remain 0.075 and 0.20. PASS additionally
815
+ requires available, positive early/middle/late Einstein slopes with relative
816
+ spread `(max-min)/median <= 0.20`. Insufficient segment data or a larger spread
817
+ produces WARNING for beta within 0.20. Above 0.20 the result is REJECT unless
818
+ the positive-intercept model agrees with observed beta within 0.05 **and**
819
+ segment stability passes; this exception permits WARNING only, never PASS.
820
+
821
+ The default reported D uses free-intercept OLS, `MSD(t) = A + 6 D t`.
822
+ For each valid candidate, diagnostics retain free-intercept D,
823
+ intercept fractions at both endpoints, and beta predicted
824
+ by log-log OLS of `b+s*t` on the actual fitting samples. No intercept is
825
+ subtracted from the measured MSD. A detected intercept effect explains model
826
+ consistency, not the physical cause of the intercept. Full-window D remains the
827
+ published estimate; segment D values never replace it. Segment diagnostics are
828
+ computed only for the selected candidate, with explicit unavailable reasons.
829
+ Relative D sensitivity `(P90-P10)/median > 0.5` also produces WARNING. These
830
+ are diagnostics, not evidence of statistical convergence. Internal thresholds
831
+ are named constants in `_msd_auto.py`; no smoothing or independent-window
832
+ sample-count assumption is used. `--mobile-site-distance A` optionally checks
833
+ the approximate MSD >= 0.5a^2 criterion using a known neighboring mobile-site
834
+ distance; this is not a universal cutoff or an inferred instantaneous ion distance.
835
+ Without it the structural ballistic cutoff is not independently determined.
836
+
837
+ `-fit-range START_PS END_PS` retains manual lag-window fitting, including its
838
+ previous upper-lag freedom; it conflicts with explicit `--fit-window auto`.
839
+ `--fit-window manual` requires a range. For example:
840
+
841
+ ```bash
842
+ pmk msd -group 0 -ne --fit-window auto
843
+ pmk msd -group 0 -ne -fit-range 500 1200
844
+ ```
845
+
846
+ Optional `-fit-method wls` and `-fit-method gls` fit the same free-intercept
847
+ Einstein model per direction, using binary nonoverlapping block samples within
848
+ the selected window. WLS uses diagonal block-error covariance and GLS includes
849
+ cross-lag correlations. At least four binary sampling levels and an identifiable
850
+ fit are required. The weighted intercepts appear in `fit-diagnostic.txt`.
851
+ The window and its quality diagnostics use OLS for all three methods.
852
+ Forced-origin fitting has been removed from the production workflow.
853
+
854
+ `-trajectory-range START END` selects a separate saved-trajectory subset in ns,
855
+ using the half-open interval `[START, END)` relative to the first original
856
+ `Time=` header, not the simulation start. GPUMD header times are in fs.
857
+ Every scanned timestamp must be finite, increasing, uniformly spaced and
858
+ consistent with `run.in`; missing timestamps/frames or unreliable thermo
859
+ alignment fail clearly. Boundary comparisons use the existing schedule-scale
860
+ tolerance `max(1e-5 fs, abs(Time)*1e-9)` for floating accumulation. Available
861
+ coverage ends one sampling interval after the last frame (thus 100000 frames
862
+ at 0.2 ps cover 20 ns). Actual selected timestamps/count are recorded.
863
+ Headers and rows before START are streamed without coordinate parsing; reading
864
+ stops at the END header when present. The suffix beyond END is not validated.
865
+ Only selected coordinates enter the existing whole-system mass-weighted COM
866
+ correction, selected individual-atom memmap and independent all-origin FFT.
867
+ Lag time restarts at zero; `-fit-range` remains an independent lag interval in ps.
868
+
869
+ Range outputs go to `msd/segments/START-ENDns/`, with shortest decimal float
870
+ values expanded without exponent or redundant trailing zeros (`0-10ns`,
871
+ `10-20ns`, `0.5-2.5ns`). Existing segment directories are refused. Full-run
872
+ outputs, other segments and root summaries are preserved; successful segment
873
+ aggregate summaries live in the segment directory. Each segment also records
874
+ `diagnostics.json`, `fit-windows.txt` and `fit-diagnostic.txt`, including REJECT.
875
+ No credible fit means no new formal D or conductivity. A 10 ns segment cannot
876
+ fit the full trajectory's 5.9–14 ns window: unchanged automatic thresholds
877
+ search only its available lags. NE uses measured thermo samples in the same
878
+ half-open global interval, after header/schedule alignment and cell checks;
879
+ segment mode never substitutes a full-run temperature or nominal fallback.
880
+ No validated uncertainty estimate or formal confidence interval is implied.
881
+ Omitting `-trajectory-range` retains the full-trajectory path.
882
+
883
+ Each successful calculation creates `msd/msd.txt` (five numeric columns: lag
884
+ time in ps, x/y/z MSD and their sum in Ų), `msd/self-diff.txt` (x/y/z/total
885
+ diffusion in cm²/s, `%.2e`) and, only with `-ne`, `msd/sigma.txt` (x/y/z/total
886
+ Nernst–Einstein conductivity in mS/cm, `%.2f`). Headers are comments. Total
887
+ diffusion and conductivity are directional arithmetic means before rounding;
888
+ display rounding may cause last-digit differences. PASS and WARNING write these
889
+ coefficients with the quality status in their comment headers. `provenance.json`
890
+ records the final quality and full-precision total coefficients.
891
+
892
+ With `-ne`, an automatic or manual window with finite, positive x/y/z/total
893
+ Einstein diffusion coefficients retains D and NE conductivity even when the fit
894
+ quality would otherwise be REJECT. The overall status becomes WARNING. The
895
+ original reason and the beta, intercept-consistency, and three-segment slope
896
+ diagnostics remain in the fit output. A WARNING can indicate that the physical
897
+ diffusion regime failed quality criteria. Without `-ne`, REJECT returns nonzero
898
+ and retains only raw MSD and fit diagnostics. PASS and WARNING retain D.
899
+
900
+ `fit-windows.txt` records evaluated candidates, rejection reasons, beta,
901
+ directional D, R², intercept, RSS, points, upper-lag origin count, intercept
902
+ diagnostics, and selected-window segment D values. `fit-diagnostic.txt` records
903
+ settings, selection, and sensitivity. Beta-qualified window sensitivity,
904
+ all-valid-candidate sensitivity, and three-segment slope spread are reported
905
+ separately. Segments and MSD time origins are correlated. Window-to-window spread
906
+ measures sensitivity. Formal statistical uncertainty requires an explicit
907
+ request. Move an existing `msd` directory aside before repeating a calculation.
908
+ Temporary coordinate storage is removed when the calculation ends.
909
+
910
+ The five-column raw MSD is published immediately after FFT succeeds, before
911
+ window search, optional uncertainty, or thermodynamic/NE processing. Later errors
912
+ retain this curve and any completed fit diagnostics. A missing valid regression,
913
+ a failed requested WLS/GLS estimator, or invalid required thermodynamic inputs
914
+ returns nonzero and prevents publication of new coefficients and aggregates.
915
+ Parsing and FFT failures occur before the raw curve is published.
916
+ FFT uses float64 atom chunks sized from an internal 128 MiB workspace budget,
917
+ with bounded remapping of time slabs to avoid retaining the entire coordinate
918
+ memmap in RAM. For 100000 frames and 784 selected atoms the temporary coordinate
919
+ file needs 1,881,600,000 bytes, plus filesystem overhead and output files.
920
+ Installation diagnostics are available with `python devtools/diagnose_msd_install.py`;
921
+ run it using the interpreter in the `pmk` shebang, since source and installed
922
+ distribution versions can differ. Both `pmk -version` and `pmk --version` work.
923
+
924
+ Optional covariance uncertainty (experimental Phase 4B.1.1):
925
+
926
+ ```text
927
+ pmk msd -group 0 --uncertainty covariance
928
+ pmk msd -group 0 -ne --uncertainty covariance --uncertainty-lag-points 100 --uncertainty-confidence 0.95
929
+ ```
930
+
931
+ Adds `self-diff-uncertainty.txt`, `uncertainty-diagnostic.txt` and, with `-ne`,
932
+ `sigma-uncertainty.txt`, using labeled JSON records. Existing point estimates and
933
+ formats remain unchanged. Available results include 68% and 95% Bayesian credible
934
+ intervals plus the requested confidence-level interval. SciPy is lazily imported.
935
+ All overlapping origins contribute to moments: `M=N_mobile*(N_frames-lag_index)`.
936
+ The continuous effective scaling parameter is `N'=N_mobile*N_frames/lag_index`,
937
+ not a literal count of disjoint intervals. The default selects 100 original lag
938
+ indices including window endpoints. The smoothing law `a*t^2/N_effective` uses
939
+ closed-form unweighted nonnegative least squares, verified against the objective
940
+ in kinisi 1.1.0 (without copying its implementation).
941
+
942
+ Continuous counts remove the artificial integer discontinuities. Diagnostics
943
+ compare raw and smoothed covariance, and Tabeart minimum-eigenvalue reconditioning
944
+ at condition limits 1e8/1e12/1e16, including eigenvalue adjustments, relative matrix
945
+ change and conditional posteriors. The threshold is lambda_max/condition_limit;
946
+ no diagonal jitter is added. Failed numerical verification remains unavailable.
947
+ Real 500 K covariance is now positive definite, but reported intervals remain
948
+ `UNAVAILABLE`: interacting-ion coverage has not been established. WARNING windows
949
+ retain conditional candidates in diagnostics only; rejected windows have none.
950
+ CLI success does not imply an available interval: inspect the uncertainty status.
951
+
952
+ Intervals are conditional on the chosen window and estimated covariance.
953
+ Interacting ions and whole-system COM correction limit the independent-particle
954
+ approximation. Covariance-parameter, window-selection, distinct-ion correlation
955
+ and Haven-ratio uncertainties are excluded. With uncertainty requested, missing
956
+ `thermo.out` uses a labeled nominal stationary NVT target; the existing ordinary
957
+ NE path still requires measured temperature. NPT remains release-blocked.
958
+ See [Phase 4B.1 report](devtools/MSD_UNCERTAINTY_PHASE4B1_REPORT.md).
959
+ The [Phase 4B.1.1 correction report](devtools/MSD_UNCERTAINTY_PHASE4B1_1_REPORT.md)
960
+ supersedes its effective-count and real-covariance conclusions. Correlated-particle
961
+ nominal 95% coverage is 67% in the corrected seeded benchmark; a narrow interval
962
+ does not demonstrate statistical convergence.
963
+
964
+ External validation is opt-in via `PYMDKIT_MSD_TEST_DATA` or:
965
+
966
+ ```text
967
+ python devtools/validate_msd_uncertainty.py --data-dir PATH --output NEW_OUTPUT_DIRECTORY
968
+ ```
969
+
970
+ Output must be a new directory outside the input dataset. The script hashes
971
+ original inputs/results before and after, regenerates missing diagnostics,
972
+ reads the original trajectory and removes temporary coordinates. Normal tests
973
+ do not require this external dataset.
974
+
975
+ After every eligible calculation succeeds, root-level `self-diff-total.txt` and,
976
+ with `-ne`, `sigma-total.txt` summarize directory, temperature (K), and the
977
+ isotropic total D (cm²/s, `%.2e`) or conductivity (mS/cm, `%.2f`). Rows use
978
+ relative paths and sort by numeric temperature, then path. Summaries use internal
979
+ unrounded totals. NE uses measured mean production temperature; without NE a
980
+ single stationary production NVT target is required (ramps, multiple targets and
981
+ missing NVT targets produce an explicit error). Genuine calculation failures return
982
+ nonzero and preserve previous summaries; skipped templates are not failures.
983
+ A successful run without `-ne` removes any stale root `sigma-total.txt`.
984
+ The companion `msd-quality-total.txt` retains each directory's PASS/WARNING
985
+ status. In NE mode, a directory whose valid coefficients were retained despite
986
+ fit-quality rejection appears as WARNING and contributes to both numeric
987
+ summaries. Without `-ne`, a directory with overall REJECT prevents publication
988
+ of new aggregates.
989
+ See [the automatic-fit report](devtools/MSD_AUTO_FIT_REPORT.md) for validation,
990
+ and [the intercept/stability update](devtools/MSD_AUTO_FIT_PHASE4A1_REPORT.md)
991
+ for the current policy, 500 K MSD comparison and limitations.
992
+
993
+ `-ne` requires a homogeneous selected element and `thermo.out`. The default
994
+ `-charge 1.0` is an explicit +1 formal-charge assumption, not inferred oxidation
995
+ state; negative charges are accepted and the sign cancels. The log records charge,
996
+ measured and target temperature, volume and fit diagnostics. Thermodynamic rows
997
+ are aligned using every run's own output interval. Volume is the absolute cell
998
+ determinant from columns 10–18, never a separate column or the initial model
999
+ volume. Only records between the first and last saved trajectory timestamps are
1000
+ averaged; shared sample times cross-check trajectory volumes. The thermo reader
1001
+ supports NPT mean volumes internally, but this does not enable NPT MSD. NVT
1002
+ volumes must be constant. Measured mean temperature enters the NE equation;
1003
+ a >5% target mismatch warns. Temperature ramps are rejected for NE.
1004
+
1005
+ Nernst–Einstein conductivity uses self-diffusion and neglects distinct-ion cross
1006
+ correlations. It is not generally equal to experimental conductivity. The existing
1007
+ `gpumd-out -msd` workflow is unchanged.
1008
+
1009
+ ## Plan GPUMD NVT production from Li MSD
1010
+
1011
+ Run the predictor from a project directory containing completed GPUMD tasks.
1012
+
1013
+ ```bash
1014
+ pmk pred-msd-time -ea 0.2 -temp-interval 50 -max-temp 550
1015
+ pmk gpumd-job -i model.xyz -nep nep.txt -in run.in -msd-time pred-msd-time.log
1016
+ ```
1017
+
1018
+ The predictor defaults to Li group 0 in grouping method 0 and selects the lowest
1019
+ eligible measured temperature. Use `-group` to select a different Li group or
1020
+ `-ref-temp 300` to select a reference by its nominal or measured temperature.
1021
+ The prediction grid advances by `-temp-interval` from the reference's nominal
1022
+ setpoint up to `-max-temp`. Each target must be above the measured reference.
1023
+ Inconsistent results at the same reference temperature require resolution
1024
+ before planning.
1025
+
1026
+ Use a completed, fixed-cell NVT production trajectory with its original
1027
+ `run.in`, `model.xyz`, and aligned `thermo.out`. The predictor requires a
1028
+ full-trajectory free-intercept OLS result from `pmk msd -ne -group 0` (or the
1029
+ matching Li group) with a +1 formal charge. PASS and WARNING are eligible. A
1030
+ baseline WARNING carries into every prediction, and REJECT excludes the fit
1031
+ from baseline selection. Successful MSD analyses write `msd/provenance.json`
1032
+ (or the equivalent file in a segment directory), which records source and
1033
+ result fingerprints, the selected group and fit, and measured thermodynamics
1034
+ when available. Older full-run results require an identifiable trajectory,
1035
+ group, fit window and quality, agreement with the saved curve and NE totals,
1036
+ and output timestamps at least as recent as the inputs. Incomplete or stale
1037
+ analyses are reported with their reason. Prediction does not rerun MSD.
1038
+
1039
+ Measured conductivity comes from the reference MSD slope and Nernst–Einstein
1040
+ (NE) relation. The forecast uses the measured reference temperature and
1041
+ conductivity with the conventional `ln(sigma*T)` Arrhenius relation.
1042
+
1043
+ ```text
1044
+ sigma(T) = sigma_r * (T_r / T) * exp[-Ea/kB * (1/T - 1/T_r)]
1045
+ D(T) = sigma(T) * V(T) * kB * T / (N_Li * q^2) [in consistent units]
1046
+ t_raw = saved_reference_ns * sqrt(D_reference / D(T))
1047
+ t_plan = ceil(max(min_production_ns, t_raw)) [ns]
1048
+ ```
1049
+
1050
+ Conductivity is independent of the volume prediction. Diffusion uses the same
1051
+ NE relation with the predicted volume and the reference Li count. With one NVT
1052
+ volume sample the volume is constant. With compatible samples (same full-cell
1053
+ composition, selected Li count and fully periodic fixed-cell convention), it
1054
+ is interpolated between measured temperatures. Targets beyond the measured
1055
+ volume range use the nearest endpoint and generate a warning. Other measured
1056
+ conductivities are compared at their actual measured temperatures. The log
1057
+ reports the absolute gap, fractional gap relative to the measurement, and
1058
+ measured-to-predicted ratio. Different fit windows limit the comparison to an
1059
+ indicative check. The supplied activation energy stays fixed.
1060
+
1061
+ The square-root scaling is an empirical planning heuristic. The default 6 ns
1062
+ is a planning floor, configurable with `-min-production-ns`. Recommended
1063
+ durations carry no guarantee of MSD convergence. Determine the actual diffusion
1064
+ regime and fit quality with `pmk msd` after production.
1065
+
1066
+ Provide a fixed timestep and use the placeholders in the production block of
1067
+ the job template. Earlier equilibration blocks can use their own numeric
1068
+ temperatures and run lengths. The template syntax below is compatible with
1069
+ GPUMD 4.2.
1070
+
1071
+ ```text
1072
+ potential nep.txt
1073
+ time_step 1.0
1074
+ ensemble npt_scr 300 300 100 0.0 100.0 1000
1075
+ run 2000000
1076
+
1077
+ ensemble nvt_bdp target_t target_t 100
1078
+ dump_thermo 10
1079
+ dump_exyz 1000 1 1
1080
+ compute_msd 5 msd-steps group 0 0
1081
+ run production-steps
1082
+ ```
1083
+
1084
+ - `production-steps` is the number of NVT MD integration steps,
1085
+ `ceil(t_plan * 1e6 / dt_fs)`.
1086
+ - `msd-steps` is GPUMD's `Nc`, the maximum number of correlation samples.
1087
+ It is `floor(0.5 * t_plan * 1e6 / (sample_interval * dt_fs))`. The sample
1088
+ interval is the first argument of the template's `compute_msd`.
1089
+ Omit the entire directive if you only need raw-trajectory `pmk msd`.
1090
+
1091
+ Pass `-in run.in` to the predictor to use the job template's timestep and
1092
+ sampling interval in the table. Otherwise the table uses the reference run's
1093
+ settings and shows a dash when the saved run has no `compute_msd`. The job
1094
+ generator uses the actual template settings and reports any recalculation.
1095
+ It validates the latest successful prediction record and the complete job
1096
+ batch, then creates one directory per target in the invocation directory.
1097
+ Existing destinations cause the batch to fail before generation. The original
1098
+ template, equilibration runs, `dump_exyz` cadence and optional
1099
+ `compute_msd` arguments are preserved.