Grid fitting#18
Closed
IVinterbladh wants to merge 9 commits into
Closed
Conversation
Add an optional `gpu` cargo feature providing a wgpu/WGSL implementation of the Direct Fourier transform (vacuum path) for fast trajectory averaging. The kernel evaluates F(q) = Σ f_i·exp(i q·r_i), |F(q)|² in f32 with one workgroup per q-vector and a shared-memory reduction over atoms; static q-vectors and atom ids stay device-resident across frames. When built with the feature, `direct` runs on the GPU by default and `--cpu` forces the CPU path; it falls back to the CPU on an active solvent model or when no adapter is available. Degenerate sizes and device-side failures return errors rather than panicking. Measured ~15x over the rayon CPU path on an Apple M4 (88,400 atoms, 1300 q-vectors), matching the CPU f64 reference to <5e-6 relative. Also add offset-scan and per-frame timing logs to trajectory averaging.
Time trajectory averaging against the number of frames actually consumed rather than the offset-table length, which overstates frames (and skews ms/frame) if XtcIterator stops early on a frame read error. Document why the GPU q-magnitudes stay f64 (form factors and q-grid match the CPU path; only the in-shader phase is f32).
Note the optional `gpu` build feature: GPU-accelerated `direct` scheme for trajectory averaging, automatic CPU fallback, and the `--cpu` opt-out.
Add GPU (wgpu) Direct Fourier transform and trajectory timing
Form-factor definitions can now be composed from several YAML files. Repeat --atomfile (or pass several paths), or give the Python Pripps constructor a list. Files are merged in order; on a duplicate species the last file wins and a warning is logged. Merging happens before symbolic resolution, so an !Alias/!United/!Linear in one file may reference a species defined in another. - formfactor.rs: split read_formfactors into parse_specs + finalize_specs; add read_formfactors_merged. - lib.rs: add Pripps::from_yaml_files; from_yaml delegates via from_formfactors. - cli.rs: --atomfile becomes Vec<PathBuf> (repeatable, order-preserving). - pripps-py: Pripps(...) accepts a str or list[str]. Split gaussian_atoms.yaml into an atomic/united-atom-only table: drop the 20 coarse-grained residue beads (byte-identical duplicates of poly_amino_acid.yaml) and 8 unused residue-level aliases, and rewrite the header. Residue-bead consumers load poly_amino_acid.yaml (or merge it with the atomic file). This resolves the mixed-representation file and supersedes the rename-only approach in #11. Closes #7
- Rename gaussian_atoms.yaml -> pepsi_atoms.yaml and document provenance: atomic five-Gaussians are Waasmaier & Kirfel (1995); united-atom groups and K=4π solvent convention are PepsiSAXS (Grudinin et al. 2017). Update all references (tests, script, README) and link DOIs inline. - Trim the README "Merging multiple files" section per review. - Use tempfile::tempdir() in the merge test to avoid fixed temp-file names colliding under parallel test runs.
Merge multiple --atomfile files; split gaussian_atoms.yaml
* Add --num-molecules: effective structure factor S_eff(q) For a periodic box of N identical molecules (the `direct` scheme, optionally XTC-averaged), `--num-molecules N` outputs the apparent structure factor and the at-concentration single-molecule form factor: S_eff(q) = |Σ_m F_m(q)|² / Σ_m |F_m(q)|² (exact, no approximation) P(q) = (1/N) · Σ_m |F_m(q)|² The box is split into N contiguous equal-size molecules and each molecule's amplitude F_m is accumulated alongside the self term Σ_m|F_m|² in DirectTransform::vacuum_intensities. Both use the box-commensurate q-vectors, so they are PBC-invariant (no unwrapping). S_eff and P are derived from the self term in Pripps::intensity and emitted as the CSV columns `p,s_eff` (and the Python .p/.s_eff getters). P(q) is the at-concentration form factor — for a flexible molecule it shifts with crowding, unlike the dilute P an experiment divides by. Guards (fail up front, before any trajectory pass): direct scheme only, vacuum only, box atom count a multiple of N, and every M-atom block must share the first block's atom-kind sequence (rejects a count that splits molecules or doesn't match the box composition). --num-molecules conflicts with --fit and runs on the CPU even with the gpu feature (the GPU kernel emits only the total |Σf|²); both are noted. XTC averaging assumes a fixed box. * Run --num-molecules on the GPU; tidy and test Extend the WGSL direct kernel to emit the per-molecule self term Σ_m|F_m|² alongside the box intensity (one workgroup per q-vector, threads stride over whole molecules), so the effective structure factor runs on the GPU instead of falling back to the CPU. Output is two f32 per q-vector; the whole-box path (no --num-molecules) is unchanged. Route DirectGpu + --num-molecules to the GPU, with the existing CPU fallback when no adapter is available. Cleanups: route average_duplicates and the 5-column averager through the shared average_by_qnorm (removing the triplicated q-binning/sort), and add an OUT_BYTES_PER_Q constant for the GPU output stride. Rename the internal Intensity carrier monomer_self -> self_term to match the local accumulators and drop the stale "monomer" naming. Tests: GPU-vs-CPU parity for the self term, and a trajectory test pinning S_eff as the ratio of frame-averaged box intensity to frame-averaged self term (ratio of averages, not the average of per-frame S_eff). * Address PR #15 review: guard zero consumed-weight-sum trajectory_average divides accumulated curves by the consumed weight sum. read_weights validates the full set, but striding can select a zero-sum subset of signed weights, which would turn every average into NaN; reject it explicitly instead. The companion review note about an empty box (0 atoms) yielding NaN S_eff is already covered upstream — Structure::from_file rejects atomless inputs before the --num-molecules guard runs — so no extra check is needed there; add a regression test and a clarifying comment. * README: derive the effective structure factor theory Replace the terse --num-molecules block with a proper derivation (GitHub LaTeX): per-molecule amplitude, the self/cross split of the box intensity, the exact P(q) and S_eff(q) definitions, and the decoupling relation S_eff = 1 + beta(S-1) with the beta-node inversion caveat. Reference the primary source for the decoupling approximation (Kotlarchyk & Chen, J. Chem. Phys. 79, 2461 (1983)). * README: fix inline math rendering on GitHub GitHub's markdown pairs the underscores in adjacent inline $...$ spans as emphasis, stripping them and breaking the math (e.g. R_m, S_eff). Switch inline math to the backtick-protected $`...`$ form, whose contents are immune to markdown; display blocks are unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A new method for fitting the parameters c1 and c2 is added - an exhaustive grid search method.
The possibility to set specific boundaries for all fit methods is added.
For grid fit number of grid points can be chosen when running Pripps.
New updated atomic form factors for amino acids and martini beads are added
Python code updated and scripts changed to fit with latest changes