…cy C) (#153)
* feat: add msd, vacf, spectrum and momentum analyses
Port the remaining thh_tools analyses into PQAnalysis:
- analysis/msd: multiple-time-origin mean square displacement with
periodic-image unwrapping (triclinic-capable) and an Einstein-relation
self-diffusion fit; `msd` CLI. Matches the legacy Diffcalc estimator
(parity <= 2e-7 against the recompiled binary).
- analysis/vacf: sliding-time-origin velocity autocorrelation with an
optional charge-flux mode (static charges or a charge trajectory) and
a windowed cosine-transform power spectrum in cm^-1 reproducing the
legacy freqcalc/fluxfreqcalc/ft pipeline (parity <= 3e-6); optional
fft-based estimator; `vacf` CLI.
- analysis/spectrum_broadening: Gaussian (optionally Lorentzian)
line broadening of stick spectra; `build_spectrum` CLI (byte-level
parity with the legacy gawk implementation).
- analysis/momentum: per-frame total linear momentum norm as a
center-of-mass drift diagnostic; `check_momentum` CLI. The single
precision parsing noise floor is documented.
All modules follow the rdf/vibrational conventions (input file readers
with documented keys, BaseWriter outputs, logging, runtime type
checking) and are registered in the pqanalysis main CLI, the console
script entry points and the user guide. Legacy-generated reference
data is checked in under tests/data; pytest-benchmark suites live in
benchmarks/analysis.
* perf: outperform legacy C analysis tools
Make the trajectory-bound analyses faster than the recompiled -O2
legacy binaries end to end, with bit-identical outputs:
- add RawTrajectoryReader: a streaming fast path yielding raw
coordinate arrays and cached Cell objects without per-frame
AtomicSystem construction, plus a single-pass block-scan frame
counter (replaces two readlines passes)
- add Cython kernels for the msd and vacf sliding-origin accumulation
(with identical-signature numpy fallbacks following the
process_lines pattern), including a lockstep charge trajectory
parser for the flux mode
- import scipy lazily (analysis import time 0.70 s -> 0.15 s)
Benchmarks (20k frames x 100 atoms, median of 3, wall clock incl.
startup, vs -O2 rebuilds of the legacy tools):
msd 1.08 s vs diffcalc 1.62 s; vacf 1.22 s vs freqcalc 1.51 s;
charge flux 1.23 s vs fluxfreqcalc 2.05 s; vacf+spectrum 1.23 s vs
freqcalc+ft 1.69 s; build_spectrum 0.24 s vs gawk 1.21 s. Outputs
match the previous implementation bitwise and legacy references to
print precision; kernel-vs-fallback equivalence is test-pinned.
* perf: parse trajectories from byte slabs
Replace the per-line parse path of the raw fast-path readers with a
Cython slab parser: frames are scanned from 8 MB byte chunks with
memchr, the atom-name token is skipped without decoding and the
numeric fields are converted with strtof/strtod directly on the
buffer. The float32 values stay bitwise identical to the previous
sscanf-based parsing (verified per frame over the full benchmark
trajectories and over adversarial rounding-boundary literals,
including subnormals and NaN payloads). A pure-python implementation
with the identical contract remains as fallback, and the charge
trajectory reader shares the same machinery.
Raw streaming of a 74 MB trajectory drops from 0.70 s to 0.16 s.
End-to-end against the fastest legacy builds (-O3/-ffast-math/-flto
where beneficial, 20k frames x 100 atoms): msd 0.54 s vs 1.55 s
(2.9x), vacf 0.65 s vs 1.49 s (2.3x), charge flux 0.66 s vs 2.03 s
(3.1x), vacf+spectrum 0.67 s vs 1.67 s (2.5x).
* chore: stop tracking generated cython artifacts
The compiled extensions produce per-platform .so files and generated
.c sources that should not live in version control (following the
existing process_lines.pyx precedent, whose .c/.so are untracked).
Remove the committed msd/vacf kernel and slab-parser artifacts and add
ignore rules; only the .pyx sources stay tracked.
* perf: vectorize rdf and speed up momentum
Bring the remaining trajectory analyses up to the msd/vacf fast path
and add a compiled histogram kernel for the pair-distance loop:
- analysis/rdf: add a Cython distance-histogram kernel (with a numpy
fallback) and route the plain g(r) case through the raw streaming
reader. The five output arrays stay bitwise identical to the
previous implementation; the residue-exclusion and in-memory paths
are untouched. End to end on 20k frames x 100 atoms this drops rdf
from 34.4 s to 0.78 s, edging past the fastest legacy C build
(0.83 s).
- analysis/momentum: read velocity trajectories through the raw fast
path (2.46 s -> 0.59 s, bit-identical norms).
- add tqdm progress bars (config-gated) to the vacf and momentum run
loops, matching rdf/msd; give vacf a class-level default window size.
Also aligns the newer modules with the rdf house style (relative
exception imports, module docstrings, CLI headings) and adds the
_slab_parser source to the sdist manifest.
* test: reach full line coverage for the new analyses
Add tests covering the remaining branches of the msd, vacf, momentum,
spectrum_broadening and raw-reader modules: the warning exception
types, the non-positive time_step and negative start guards, the
non-fast-path trajectory-reader branches (extended xyz velocity and
charge inputs), the charge-trajectory length and shape errors, the
zero origin-norm case, and the byte-slab parser edge cases (missing
trailing newline, blank-line skipping, truncated frames, invalid box
counts, empty qmcfc frames). The compiled-extension import fallbacks
are exercised without disturbing the shared modules. Line coverage of
the added source is now 100%.
Summary
Release
Tag
v1.4.0after this PR merges and all checks pass.